# TrulyNatural SDK -- agent documentation (full Markdown bundle) > Every Markdown page in this bundle concatenated into one file. > Each page is preceded by ``. Canonical HTML site: https://doc.sensory.com/tnl/7.8/ --- source_path: "agent-tools.md" canonical_url: "https://doc.sensory.com/tnl/7.8/agent-tools/" --- # Coding agents This site publishes a [machine-readable index](https://doc.sensory.com/tnl/7.8/llms.txt) and a [per-page Markdown mirror][llmstxt] designed for AI coding tools. Pointing your editor at the index is the only setup step; after that "how do I push audio?" / "add Sensory to my CMake build" / "enroll a UDT in Java" land on the right page without further configuration. [llmstxt]: https://llmstxt.org/ ## Editor setup Register [`https://doc.sensory.com/tnl/7.8/llms.txt`](https://doc.sensory.com/tnl/7.8/llms.txt) once. Common editors: **Cursor** **Settings → Indexing & Docs → Add Doc**, paste the URL, give it a name (e.g. `Sensory TrulyNatural SDK`). Reference the doc set with `@Docs Sensory TrulyNatural SDK` in chat. **Claude Code** Add the URL to a project-level `CLAUDE.md` so the agent reads the index on every session: ```markdown # Documentation - TrulyNatural SDK: https://doc.sensory.com/tnl/7.8/llms.txt Use this index to find SDK pages; prefer the linked `.md` URLs over general web search. ``` **GitHub Copilot Chat** Reference individual pages with `#fetch` (e.g. `#fetch https://doc.sensory.com/tnl/7.8/api/inference.md`). Copilot does not ingest a documentation index globally; the per-page `.md` URLs in this site's [`manifest.json`](https://doc.sensory.com/tnl/7.8/manifest.json) are the unit of context. **Aider, Continue, Cline** These tools accept Markdown URLs in their `--read` / `/add` / context commands. Point them at individual `.md` pages from `manifest.json` rather than the full bundle: each page is sized for a single chat turn, while [`llms-full.txt`](https://doc.sensory.com/tnl/7.8/llms-full.txt) is a single ~1.3 MiB file better suited to bulk offline indexing. **Other** Any tool that follows an AI-oriented documentation index typically accepts either an `llms.txt`-style entry point or a sitemap of Markdown URLs. The two relevant URLs are: - Index: [`https://doc.sensory.com/tnl/7.8/llms.txt`](https://doc.sensory.com/tnl/7.8/llms.txt) - Per-page mirror: each entry in [`manifest.json`](https://doc.sensory.com/tnl/7.8/manifest.json) carries a `path` (relative to the index) and a `canonical_url` (rendered HTML URL). Both `.md` and HTML serve identical content. ## What's in the bundle Three files share the same content rendered three ways: - [`llms.txt`](https://doc.sensory.com/tnl/7.8/llms.txt) — orientation index (~27 KiB). Curated **Common tasks** and **Start here** routes plus a section by path prefix. This is the file most tools want. - [`manifest.json`](https://doc.sensory.com/tnl/7.8/manifest.json) — a JSON index of every page with `path`, `bytes`, `title`, `canonical_url`, an optional `headings` outline on reference pages, and an optional `last_modified` (ISO 8601 UTC) for incremental re-ingest. Useful for budgeting context size or programmatically picking pages. - [`llms-full.txt`](https://doc.sensory.com/tnl/7.8/llms-full.txt) — every Markdown page concatenated into one file (~1.3 MiB), with a `` header per page. Reserve this for bulk offline indexing; for day-to-day chat, fetch individual `.md` URLs instead so the model isn't carrying the whole SDK in its context window. ## Day-to-day usage tips - **Prefer per-page `.md` URLs over the full bundle.** Each rendered page also exists as a `.md` next to its HTML (e.g. [`api/inference.md`](https://doc.sensory.com/tnl/7.8/api/inference.md) beside the rendered [API reference](api/inference.md)). Pasting one of these into a chat is usually enough context. - **Use `#fragment` URLs for narrow questions.** All H2/H3/H4 headings have stable anchors. For a question like "what does `snsrLoad` return?", paste `https://doc.sensory.com/tnl/7.8/api/inference.md#load` rather than the whole page. The `## Symbols` section of `llms.txt` lists every C/Java entry point with its anchor for direct deep-linking. - **Use Common tasks for typical work.** The first section of `llms.txt` is curated to match natural-language prompts: "first program", "build integration", "push audio", "wake word then LVCSR or STT", "enroll a UDT in Java", and a dozen more. Most agent prompts will resolve through one of these routes. - **Re-pin the URL on each SDK upgrade.** This site publishes a per-version doc tree (`/tnl/7.8/`); when you move to a new SDK release, point your editor at the new version's `llms.txt`. The [`/tnl/latest/`](/tnl/latest/llms.txt) alias always redirects to the most recent published version if you'd rather track HEAD. ## Programmatic ingestion If you're writing a tool, not registering URLs in an editor: ```python import json, urllib.request base = "https://doc.sensory.com/tnl/7.8/llms.txt".rsplit("/", 1)[0] with urllib.request.urlopen(f"{base}/manifest.json") as r: manifest = json.load(r) # manifest["version"] == 2; manifest["entries"] is a list of dicts. for page in manifest["entries"]: if page["bytes"] < 8192: # small reference page with urllib.request.urlopen(f"{base}/{page['path']}") as r: text = r.read().decode("utf-8") # ingest `text` keyed on page["canonical_url"] ``` The `canonical_url` field is the most stable join key across the two representations: the same string identifies a page in the loose on-host mirror, in `manifest.json`, in `llms-full.txt`'s `` headers, and as a hyperlink target inside other pages. ## See also - The [`llms.txt` proposal][llmstxt] this site implements. - The [Coding agents callout](index.md) on the home page. - The [changelog entry](changes/index.md) describing the bundle. *[API]: Application Programming Interface *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[SDK]: Software Development Kit *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets --- source_path: "api/build-system.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/build-system/" --- # Integrate with your build This describes how to add the TrulyNatural SDK to your own application's build system. We support [CMake](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-cmake) (recommended), [Make](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-make), [Java](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-java), [Gradle on Android](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-android), and [Xcode iOS](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-ios). The paths below assume the default online documentation install location, _$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9_. If you installed the SDK elsewhere, replace that prefix with your SDK installation directory. Offline SDK documentation uses the actual installed path. If you're using a different build system, take a look at the compiler and linker flags you'll need listed for [Make](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-make). ## CMake - recommended Add this to your _CMakeLists.txt_ files: ```cmake list(APPEND CMAKE_MODULE_PATH "$ENV{HOME}/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9") include(SnsrLibrary) ``` and to each of your executable targets: ```cmake target_link_libraries(your-target SnsrLibrary) ``` If you do not want to include any OSS components (and therefore no STT support) use `SnsrLibraryOmitOSS` instead: ```cmake target_link_libraries(your-target SnsrLibraryOmitOSS) ``` **Also see these related items:** [CMakeLists.txt](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#cmakeliststxt) in the [C examples](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#c-examples) section. ## Make Set the compiler and linker flags to allow your toolchain to find the `` header and the platform-specific `libsnsr.a`. **Also see these related items:** [Makefile](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#makefile) in the [C examples](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#c-examples) section. ### Linux ```make SNSR_ROOT ?= $(HOME)/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9 CFLAGS += -I$(SNSR_ROOT)/include LDFLAGS += -L$(SNSR_ROOT)/lib/ LDLIBS += -lsnsr -lasound -lpthread -lm -ldl -lstdc++ ``` Where `` should be the output of `gcc -dumpmachine` _(stt)_ `-lstdc++` is needed for the TrulyNatural STT SDK only. ### macOS ```make SNSR_ROOT ?= $(HOME)/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9 CFLAGS += -I$(SNSR_ROOT)/include LDFLAGS += -L$(SNSR_ROOT)/lib/macos LDLIBS += -lsnsr -framework AudioToolbox -framework Accelerate \ -framework CoreFoundation -framework Foundation -lm -lstdc++ ``` _(stt)_ `-lstdc++` is needed for the TrulyNatural STT SDK only. ### Windows Use Visual Studio 2022 or later. ```make SNSR_ROOT ?= $(HOME)/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9 CFLAGS += -I$(SNSR_ROOT)/include LDFLAGS += -L$(SNSR_ROOT)/lib/x86_64-windows-msvc LDLIBS += snsr.lib winmm.lib user32.lib ``` ## Java The Java binding uses JNI to load the native library. Use the Sensory JAR from the SDK Maven repository at _$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/m2repository_ plus a native library search path (`java.library.path`) pointing at _$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/lib/_ (for example _$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/lib/macos_ on macOS). Maven coordinates (desktop JAR, not the Android `@aar`): ```gradle implementation "com.sensory.speech.snsr:tnl:7.8.0-pre.0" ``` On Linux, set `` to the output of `gcc -dumpmachine`. On macOS use `macos`. On Windows use the MSVC library directory under _$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/lib_ (for example `x86_64-windows-msvc`). For Gradle, derive the SDK root from the Maven repository directory (its parent is the SDK install directory) and pass the native library directory to the `run` task (see [Your first program](https://doc.sensory.com/tnl/7.8/getting-started/your-first-program.md#your-first-program)). **Also see these related items:** [Java examples](https://doc.sensory.com/tnl/7.8/api/sample/java/index.md#java-examples). ## Android * If using live audio recording, add the `RECORD_AUDIO` [permission][] to the application's _AndroidManifest.xml_ file: ```xml ``` * Add to _settings.gradle_: ```gradle def snsrRepository = providers.gradleProperty("SNSR_REPOSITORY").get() def snsrRepositoryFile = file(snsrRepository) if (!snsrRepositoryFile.isAbsolute()) { snsrRepositoryFile = file("${System.getProperty('user.home')}/${snsrRepository}") } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() maven { url = snsrRepositoryFile.toURI() } mavenLocal() } } ``` * Add to _app/build.gradle_: ```gradle /// snsr model utilities apply from: '../gradle/model-utils.gradle' configurations { snsr_model } dependencies { // TrulyNatural code library implementation "com.sensory.speech.snsr:${SNSR_LIB_TYPE}:${SNSR_LIB_VERSION}@aar" // Any `snsr` task models needed by your app in Maven GAV format, for example snsr_model "com.sensory.speech.snsr.model:udt-universal:3.66.1.9@snsr" } ``` * Copy _util/model-utils.gradle_ from the TrulyNatural installation directory to _gradle/model-utils.gradle_ in your application. * Add configuration settings to _gradle.properties_: ```gradle # Sensory TrulyNatural configuration # Relative to the user's home directory; use an absolute path for custom installs. SNSR_REPOSITORY=Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/m2repository SNSR_LIB_TYPE=tnl SNSR_LIB_VERSION=7.8.0-pre.0 ``` **Also see these related items:** [Android examples](https://doc.sensory.com/tnl/7.8/api/sample/android/index.md#android-examples). ## iOS - Add a Bridging header, _ProjectName-Bridging-Header.h_, that includes `#!swift #import ` - Select the application target. - In "Capabilities", add "Inter-App Audio Capability". - In "Info" > "Custom iOS Target Properties", add an `NSMicrophoneUsageDescription` string. - In "Build Settings", - Add `${SNSR_ROOT}/include` to the "Header Search Paths". - Add `${SNSR_ROOT}/lib/ios` to the "Library Search Paths". - Add `-lsnsr` to "Other Linker Flags". - In "General" > "Frameworks, Libraries, and Embedded Content", - Add `Accelerate.framework` - Add `AudioToolbox.framework` - Select the project. - Select the "Editor > Add Build Setting > Add User-Defined Setting" menu entry. - Add `SNSR_ROOT`. Set this variable to the TrulyNatural SDK installation directory, _$(HOME)/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9_ **Also see these related items:** [iOS examples](https://doc.sensory.com/tnl/7.8/api/sample/ios/index.md#ios-examples). [permission]: https://developer.android.com/guide/topics/security/permissions.html "Permissions on Android" *[API]: Application Programming Interface *[OSS]: Open-source software *[SDK]: Software Development Kit *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets --- source_path: "api/constants.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/constants/" --- # Constants These are preprocessor macros or module constants available during the application build phase. They contain library information such as the SDK variant and version. **Example:** **C/C++** ```c #include int main(int argc, char *argv[]) { SnsrRC r; printf("This is %s SDK version %s\n", SNSR_NAME, SNSR_VERSION); return 0; } ``` **Java** ```java import com.sensory.speech.snsr.Snsr; public class segmentSpottedAudio { public static void main(String[] args) { System.out.println("This is " + Snsr.NAME + " SDK version " + Snsr.VERSION); } } ``` ## Variant Constants in this section describe the SDK library type: _TrulyHandsfree_ (fixed and enrolled wake words) or _TrulyNatural_ (_TrulyHandsfree_ with LVCSR and STT). ### IS_TRULYHANDSFREE **C/C++** ```c #define SNSR_IS_TRULYHANDSFREE 0 ``` **Java** ```java public class Snsr { public final static int IS_TRULYHANDSFREE = 0; } ``` `1` if this SDK is TrulyHandsfree, `0` if not. ### IS_TRULYNATURAL **C/C++** ```c #define SNSR_IS_TRULYNATURAL 1 ``` **Java** ```java public class Snsr { public final static int IS_TRULYNATURAL = 1; } ``` `1` if this SDK is TrulyNatural, `0` if not. ### NAME **C/C++** ```c #define SNSR_NAME "TrulyNatural" ``` **Java** ```java public class Snsr { public final static String NAME = "TrulyNatural"; } ``` SDK variant: `"TrulyHandsfree"` or `"TrulyNatural"`. ### SETTING_SZ **C/C++** ```c #define SNSR_SETTING_SZ 128 ``` **Java** ```java public class Snsr { public final static int SETTING_SZ = 128; } ``` The longest supported setting key length in bytes, including the terminating `\0`. ## Version These describe the TrulyNatural SDK API version and the [component parts][semver] of the version string. ### VERSION **C/C++** ```c #define SNSR_VERSION "7.8.0-pre.0+682.g276c2541e9" ``` **Java** ```java public class Snsr { public final static String VERSION = "7.8.0-pre.0+682.g276c2541e9"; } ``` API version. This follows [semantic versioning][semver] rules. ### VERSION_MAJOR **C/C++** ```c #define SNSR_VERSION_MAJOR 7 ``` **Java** ```java public class Snsr { public final static int VERSION_MAJOR = 7; } ``` API major version number. Incremented for changes that are **not** backwards-compatible, but also to indicate major improvements in technology that **are** backwards-compatible. Refer to the [release notes](https://doc.sensory.com/tnl/7.8/changes/index.md#v7-changes) for details. ### VERSION_MINOR **C/C++** ```c #define SNSR_VERSION_MINOR 8 ``` **Java** ```java public class Snsr { public final static int VERSION_MINOR = 8; } ``` API minor version number. Incremented for changes and improvements that are backwards-compatible. ### VERSION_PATCH **C/C++** ```c #define SNSR_VERSION_PATCH 0 ``` **Java** ```java public class Snsr { public final static int VERSION_PATCH = 0; } ``` API patch version number. Incremented for bug fixes. ### VERSION_PRE **C/C++** ```c #define SNSR_VERSION_PRE "pre.0" ``` **Java** ```java public class Snsr { public final static String VERSION_PRE = "pre.0"; } ``` Pre-release version tag. This is empty for official releases. ### VERSION_BUILD **C/C++** ```c #define SNSR_VERSION_BUILD "682.g276c2541e9" ``` **Java** ```java public class Snsr { public final static String VERSION_BUILD = "682.g276c2541e9"; } ``` Build information. This is empty for official releases. ### VERSION_CMAKE **C/C++** ```c #define SNSR_VERSION_CMAKE "7.7.0.715" ``` **Java** ```java public class Snsr { public final static String VERSION_CMAKE = "7.7.0.715"; } ``` API version compatible with [CMAKE_PROJECT_VERSION][]. [CMAKE_PROJECT_VERSION]: https://cmake.org/cmake/help/latest/variable/CMAKE_PROJECT_VERSION.html ### VERSION_ID **C/C++** ```c #define SNSR_VERSION_ID 98 ``` **Java** ```java public class Snsr { public final static int VERSION_ID = 98; } ``` Unique release counter. This value is incremented with each public SDK release. ### VERSION_DSP **C/C++** ```c #define SNSR_VERSION_DSP "8.5.2" ``` **Java** ```java public class Snsr { public final static String VERSION_DSP = "8.5.2"; } ``` DSP embedded library version. [semver]: http://semver.org/ "Semantic versioning specification" *[API]: Application Programming Interface *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[SDK]: Software Development Kit *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/heap.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/heap/" --- # Memory management This section describes heap memory management used by the TrulyNatural SDK C language binding. The Java binding uses the standard garbage collecting approach. SDK handles ([Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session), [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream), [Callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback)) are [reference-counted](https://doc.sensory.com/tnl/7.8/api/heap.md#reference-counting). Manage the lifetime of these objects with [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) and [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release). Objects are created with a reference count of zero. This makes it cleaner to use a new object as a function argument without having to keep a handle to it just to be able to release it afterwards. This library uses a small amount of heap memory to keep track of library-wide configuration options. You can use [tearDown](https://doc.sensory.com/tnl/7.8/api/heap.md#teardown) to free these allocations. ## Best practices * If you keep a reference to a handle, call [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) on it to increment the reference count. * Call [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) before giving up the reference. This will decrease the reference count and deallocate the object one the reference count is `<= 0`. * Functions that take reference-counted objects as arguments must * Call [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) on function entry for each of these arguments. * Call [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) on function exit for each of these arguments, except for the ones where long-running references were kept. * Follow this retain/release procedure even when the function returns an error condition, as it allows for convenient function composition without memory leaks. ## Reference counting ### release **C/C++** ```c SNSR_API void snsrRelease(const void *handle); ``` **Parameters and return value:** **Input parameter:** `handle` * A reference-counted object, or `NULL`. Releases an object reference. Decrements the reference count on `handle`. If the reference count drops to zero (or below), this will deallocate `handle`. When this function returns `handle` will no longer be valid. Accessing a released `handle` in any way will lead to [undefined behavior][undefined-behavior]. **Note:** `handle` must be `NULL`, or a valid reference-counted object returned by this library, such as [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session), [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream), or [Callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback) handle, or a `const char *` returned by [getString](https://doc.sensory.com/tnl/7.8/api/inference.md#getters). Behavior on any other pointer is undefined and will likely lead to the process calling `abort()`. **Also see these related items:** [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release), [Callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback), [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session), [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream), [getString](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) ### retain **C/C++** ```c SNSR_API void snsrRetain(const void *handle); ``` **Parameters and return value:** **Input parameter:** `handle` * A reference-counted object. Retains a reference to an object. Increments the reference count on `handle`. The `handle` will remain valid until you call [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) on it. To avoid memory leaks, be sure to match each call to [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) with exactly one call to [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release). **Note:** `handle` must be a valid reference-counted object returned by this library, such as [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session), [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream), or [Callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback) handle, or a `const char *` returned by [getString](https://doc.sensory.com/tnl/7.8/api/inference.md#getters). Behavior on any other pointer (including `NULL`) is undefined and will likely lead to the process calling `abort()`. **Also see these related items:** [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release), [Callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback), [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session), [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream), [getString](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) ## Heap allocation You can replace the standard library heap allocator used by the TrulyNatural SDK with one of the provided [heap allocators](https://doc.sensory.com/tnl/7.8/api/library-config.md#heap-allocators), or one of your [own design](https://doc.sensory.com/tnl/7.8/api/library-config.md#user-defined-allocator). The functions in this section provide replacements for `malloc()`, `realloc()`, and `free()` that use this heap allocator. These are for convenience only, they're not used or required by the TrulyNatural SDK API. ### malloc **C/C++** ```c SNSR_API void * snsrMalloc(size_t size); ``` **Parameters and return value:** **Input parameter:** `size` * Number of bytes to allocate on the heap. **Return value:** * Pointer to the start of a memory block at least `size` bytes long. Allocate memory with TrulyNatural SDK allocator. This function works like `malloc()`, but uses this SDK's dynamic memory allocator instead. This is provided for convenience only, it is not used or required by the library API. **Note:** `snsrMalloc()` will never return `NULL`. A failed memory allocation results in a library-wide panic. You can provide a custom panic function with [PANIC_FUNC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_panic_func). **Also see these related items:** [heap allocators](https://doc.sensory.com/tnl/7.8/api/library-config.md#heap-allocators), [free](https://doc.sensory.com/tnl/7.8/api/heap.md#free), [realloc](https://doc.sensory.com/tnl/7.8/api/heap.md#realloc) ### free **C/C++** ```c SNSR_API void snsrFree(void *ptr); ``` **Parameters and return value:** **Input parameter:** `ptr` * `NULL`, or an allocation previously returned by [malloc](https://doc.sensory.com/tnl/7.8/api/heap.md#malloc) or [realloc](https://doc.sensory.com/tnl/7.8/api/heap.md#realloc). Free heap memory allocated on the TrulyNatural SDK heap. This function works like `free()`, but uses this library's dynamic memory allocator. The `ptr` parameter must be `NULL` or be an allocation returned by either `snsrMalloc()` or `snsrRealloc()`. Any other value will result in undefined behavior. This is provided for convenience only, it is not used or required by the library API. **Also see these related items:** [heap allocators](https://doc.sensory.com/tnl/7.8/api/library-config.md#heap-allocators), [malloc](https://doc.sensory.com/tnl/7.8/api/heap.md#malloc), [realloc](https://doc.sensory.com/tnl/7.8/api/heap.md#realloc) ### realloc **C/C++** ```c SNSR_API void * snsrRealloc(void *ptr, size_t size); ``` **Parameters and return value:** **Input parameter:** `ptr` * Allocation returned by [malloc](https://doc.sensory.com/tnl/7.8/api/heap.md#malloc) or [realloc](https://doc.sensory.com/tnl/7.8/api/heap.md#realloc), or `NULL`. **Input parameter:** `size` * Number of bytes to allocate on the heap. **Return value:** * Pointer to the start of a memory block at least `size` bytes long. Resize a heap block allocated on the TrulyNatural SDK heap. This function works like `realloc()`, but uses this library's dynamic memory allocator. The `ptr` parameter must `NULL`, or contain a value returned by `snsrMalloc()` or `snsrRealloc()`. Any other value will result in undefined behavior. This is provided for convenience only, it is not used or required by the library API. **Note:** `snsrRealloc()` will never return `NULL`. A failed memory allocation results in a library-wide panic. You can provide a custom panic function with [PANIC_FUNC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_panic_func). **Also see these related items:** [heap allocators](https://doc.sensory.com/tnl/7.8/api/library-config.md#heap-allocators), [free](https://doc.sensory.com/tnl/7.8/api/heap.md#free), [malloc](https://doc.sensory.com/tnl/7.8/api/heap.md#malloc) ## Free library resources ### tearDown **C/C++** ```c SNSR_API SnsrRC snsrTearDown(void); ``` **Parameters and return value:** **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. Releases library-wide resources. Resets the TrulyNatural SDK library to the initial defaults and releases all library-wide resources. Calling this function is optional. It is most useful to suppress false positives when tracking down heap leaks with a tool such as [Valgrind][]. **Warning:** Do **not** call this function unless all SDK handles have been released. Doing so will lead to [undefined behavior][undefined-behavior]. **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) [undefined-behavior]: https://en.wikipedia.org/wiki/Undefined_behavior "Undefined program behavior" [Valgrind]: https://en.wikipedia.org/wiki/Valgrind "Valgrind is a programming tool for memory debugging, memory leak detection, and profiling" *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/index.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/" --- # API reference This section provides reference documentation for the TrulyNatural SDK API. This includes both the native [C][] and the [Java][] interfaces. [Overview](https://doc.sensory.com/tnl/7.8/api/overview.md#api-overview) - Design goals and high-level overview of how everything fits together. Start here. - New to embedding? See [Your first program](https://doc.sensory.com/tnl/7.8/getting-started/your-first-program.md#your-first-program). [Inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference) - Functions, classes, and methods for evaluating models. [I/O](https://doc.sensory.com/tnl/7.8/api/io.md#input-and-output) - Streamed input and output adapters. [Inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference) uses these for all binary and text input and output. [Constants](https://doc.sensory.com/tnl/7.8/api/constants.md#constants) - TrulyNatural SDK metadata available during the compile or build phase, for example the SDK [VERSION](https://doc.sensory.com/tnl/7.8/api/constants.md#version). [Setting keys](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) - Settings are strings used as keys in [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) [inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference) object function or method calls. This section provides an exhaustive list of all supported keys. [Library configuration](https://doc.sensory.com/tnl/7.8/api/library-config.md#library-configuration) - Describes functions and settings that control overall TrulyNatural SDK library behavior. - These are most useful on small platforms with limited memory, and relevant to the native C API only. Library configuration is not available in other language bindings. [Memory management](https://doc.sensory.com/tnl/7.8/api/heap.md#memory-management) - Describes heap memory management used by the TrulyNatural SDK C language binding. The Java binding uses the standard garbage collecting approach. [Integrate with your build](https://doc.sensory.com/tnl/7.8/api/build-system.md#integrate-with-your-build) - Describes how to add the TrulyNatural SDK to your own application's build system. [C examples](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#c-examples) - Sample code that uses the C API. [Java examples](https://doc.sensory.com/tnl/7.8/api/sample/java/index.md#java-examples) - Sample code that uses the Desktop Java API. [Android examples](https://doc.sensory.com/tnl/7.8/api/sample/android/index.md#android-examples) - Sample code that uses Java on Android. [iOS examples](https://doc.sensory.com/tnl/7.8/api/sample/ios/index.md#ios-examples) - Sample code that uses [Swift][] with a bridging header to the C API. [C]: https://en.wikipedia.org/wiki/C_(programming_language) "C programming language" [Java]: https://en.wikipedia.org/wiki/Java_(programming_language) "Java programming language" [Swift]: https://en.wikipedia.org/wiki/Swift_(programming_language) "Swift programming language" *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/inference.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/inference/" --- # Inference [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instances encapsulate the entire runtime state for a model. Once you've created a new instance with [new](https://doc.sensory.com/tnl/7.8/api/inference.md#new) and [loaded](https://doc.sensory.com/tnl/7.8/api/inference.md#load) a model, you can access the model's [setting keys](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) with the typed [getters](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) and [setters](https://doc.sensory.com/tnl/7.8/api/inference.md#setters). Use [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) to register [callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback) functions tied to specific [events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events). Call [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) or [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) to run model inference. Most-used [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) operations: | Function | Summary | |----------|---------| | [new](https://doc.sensory.com/tnl/7.8/api/inference.md#new) | Create an empty session handle. | | [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) | Load a model from a file, [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream), or memory. | | [getters](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) / [setters](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) | Read and write [setting keys](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) with the matching type. | | [set](https://doc.sensory.com/tnl/7.8/api/inference.md#set) | Apply one or more `key=value` settings from a string. | | [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) | Bind a [callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback) to an [event](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) or [iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators). | | [forEach](https://doc.sensory.com/tnl/7.8/api/inference.md#foreach) | Walk a list-valued setting through repeated callback invocations. | | [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) | Process attached stream input until finished or [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop). | | [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) | Process one audio chunk per call for live or streaming input. | | [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require) | Verify task type, library version, or other prerequisites. | | [reset](https://doc.sensory.com/tnl/7.8/api/inference.md#reset) | Reset session to its initial state (errors, buffers, results, counters). | Return codes and error inspection: [clearRC](https://doc.sensory.com/tnl/7.8/api/inference.md#clearrc), [errorDetail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail), [rC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), and the [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) enumeration. C↔Java error-handling differences are summarized in [API overview](https://doc.sensory.com/tnl/7.8/api/overview.md#api-overview). ## Callback [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) reports [events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) and steps through [iterations](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators) by calling these user-defined functions or methods. ### callback **C/C++** ```c typedef struct SnsrCallback_ *SnsrCallback; typedef SnsrRC (*SnsrHandler)(SnsrSession s, const char *key, void *data); typedef void (*SnsrDataRelease)(const void *data); SNSR_API SnsrCallback snsrCallback(SnsrHandler h, SnsrDataRelease r, void *data); ``` **Parameters and return value:** **Input parameter:** `h` * The function to call when this callback is invoked. **Input parameter:** `r` * A function that releases memory allocated for `data`, called when the returned handle is destroyed. Use `NULL` if there's no clean-up required. **Input parameter:** `data` * User-defined private value, not used by the SDK. **Return value:** * `snsrCallback`: A new callback handle instance, or `NULL` if one could not be created. **Input parameter:** `s` * The [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle the callback was registered with. **Input parameter:** `key` * Name of the invoked [event](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) or [iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators) setting. **Return value:** * `SnsrHandler`: [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) if all is well. Errors are reported to the code that invoked the callback. `snsrCallback` creates a new `SnsrCallback` instance. These are used to invoke library [event](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) handlers and [iterators](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators). * New handles have a reference count of `0`. Use [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) if keeping a reference and [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) to release such a reference. * The session will call function `h` when the callback is invoked. * The allocator will call `r` to release `data` just before the `SnsrCallback` is deleted. Callbacks happen on the same thread that the [forEach](https://doc.sensory.com/tnl/7.8/api/inference.md#foreach), [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), or [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) function was called on. Task processing is single-threaded and pauses until the callback function returns. Best practice is to do as little processing as possible in callback handlers. `SnsrHandler` instances are user-defined functions that process event callbacks issued by [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session). `SnsrDataRelease` instances are user-defined functions called to release the `data` parameter. **Also see these related items:** [events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events), [iterators](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators), [forEach](https://doc.sensory.com/tnl/7.8/api/inference.md#foreach), [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler), [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run), [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) **Java** _The Java language binding uses the [SnsrSession.Listener](https://doc.sensory.com/tnl/7.8/api/inference.md#listener) interface for event and iteration callbacks._ ## Session **C/C++** ```c typedef struct SnsrSession_ *SnsrSession; ``` `SnsrSession` is the TrulyNatural SDK API inference type. Session handles contain the entire state for a task. If a `SnsrSession` handle has to be shared across threads, all calls into this library that use the handle **must** be protected by application-level thread synchronization calls. The `SnsrSession` API calls are not re-entrant. Synchronization and locking are not needed if each instance is accessed from a single thread only. Best practice is to use a single thread per handle. Using multiple handles per thread is fully supported. **Java** ```java public class SnsrSession {} ``` `SnsrSession` is the TrulyNatural SDK inference class. Session handles contain the entire state for a task. Instance method calls are not re-entrant. If these are called from different threads, all such calls must be protected by application-level synchronization. Methods that are not explicitly used to query the state return the instance itself, to support method chaining. **Example:** ```java import com.sensory.snsr.SnsrSession; SnsrSession s = new SnsrSession() .load("task-data.snsr") .require(Snsr.TASK_TYPE, Snsr.PHRASESPOT); ``` ### Listener #### onEvent **C/C++** _The C language binding uses [Callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback) for event and iteration handlers._ **Java** ```java public interface Listener { public SnsrRC onEvent(SnsrSession s, String key); } ``` **Parameters and return value:** **Input parameter:** `s` * The [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance that invoked the method. **Input parameter:** `key` * Name of the invoked [event](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) or [iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators) setting. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) if all is well. Errors are reported to the code that invoked the callback. [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) reports [events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) and steps through [iterations](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators) by calling this method. Callbacks happen on the same thread that the [forEach](https://doc.sensory.com/tnl/7.8/api/inference.md#foreach), [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), or [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) method was called on. Task processing is single-threaded and pauses until the `onEvent` method returns. Best practice is to do as little processing as possible in callback handlers themselves. Return [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) to continue processing, or any other [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) value to stop. **Note:** `SnsrSession.Listener` is a functional interface, so you can use a lambda expression instead of passing an object that implements `Listener`: ```java session.setHandler(Snsr.RESULT_EVENT, (session, key) -> { System.out.println(String.format("Recognized \"%s\"", session.getString(Snsr.RES_TEXT))); return SnsrRC.OK; }); ``` **Also see these related items:** [events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events), [iterators](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators), [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler), [forEach](https://doc.sensory.com/tnl/7.8/api/inference.md#foreach), [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) ### clearRC **C/C++** ```c SNSR_API void snsrClearRC(SnsrSession s); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. Clears the session error code. Once a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) error occurs (a return code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) is reported), all library calls on the session handle will immediately return with the same error code. Call this function to clear the error detail and reset the code to [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok). **Also see these related items:** [reset](https://doc.sensory.com/tnl/7.8/api/inference.md#reset) ### describeError **C/C++** ```c SNSR_API void snsrDescribeError(SnsrSession s, const char *format, ...); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Input parameter:** `format` * `printf()` style format string. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java public void describeError(String format, Object... args); ``` **Parameters and return value:** **Input parameter:** `format` * `String.format()` style format string. **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. Sets the detailed session error message. `describeError` sets the message returned by `errorDetail`. Use this to propagate a human-readable error message generated by a callback function to the session handle. **Also see these related items:** [errorDetail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail) ### dup **C/C++** ```c SNSR_API SnsrRC snsrDup(SnsrSession s, SnsrSession *dst); ``` **Parameters and return value:** **Input parameter:** `s` * Source [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Output parameter:** `dst` * Pointer to memory allocated for a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java public SnsrSession dup(); ``` **Parameters and return value:** **Return value:** * A duplicate instance of [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session). Duplicates a session handle. Creates a new [session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle that is a clone of a source handle. This function is roughly equivalent to: **C/C++** ```c SnsrStream b = snsrStreamFromBuffer(1024, 1073741824); snsrSave(s, SNSR_FM_CONFIG, b); snsrLoad(*dst, b); snsrRelease(b); ``` **Java** ```java SnsrStream buf = SnsrStream.fromBuffer(1024, 1073741824); a.save(SnsrDataFormat.CONFIG, buf); SnsrSession b = new SnsrSession().load(buf); buf.release(); buf = null; ``` The new session `dst` contains all of the [configuration](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#configuration) from the source session, but none of the [runtime](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#runtime) settings. Immutable configuration settings (such as acoustic models) are shared between the source and `dst`. Using `dup` to create two runtime instances of a task will use less memory than loading the same task data into two session handles. **Also see these related items:** [new](https://doc.sensory.com/tnl/7.8/api/inference.md#new), [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) ### errorDetail **C/C++** ```c SNSR_API const char * snsrErrorDetail(SnsrSession s); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Return value:** * An error message describing the most recent reason for failure. The memory pointed to is owned by this library and most not be released. It is not reference-counted, calling [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) or [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) on this handle will panic the heap allocator. The handle remains valid only until the next function call on `s`. **Java** ```java public String errorDetail(); ``` **Parameters and return value:** **Return value:** * An error message describing the most recent reason for failure. Retrieves a detailed session error message. This human-readable error message should be used for display or logging only. The content of the message is system-specific. Do not parse this to determine program flow, use the [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) return code instead. **Also see these related items:** [describeError](https://doc.sensory.com/tnl/7.8/api/inference.md#describeerror), [rC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc-method) ### forEach **C/C++** ```c SNSR_API SnsrRC snsrForEach(SnsrSession s, const char *key, SnsrCallback c); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Input parameter:** `key` * [Iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators) key. **Input parameter:** `c` * A [callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback) instance invoked for each iteration. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. Calls a user function for each iteration over a list. Invokes the callback function for each iteration over iterator setting `key`. If the callback returns an error (i.e. not [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok)) the iteration loop is terminated early, and `forEach` returns this result code. **Also see these related items:** [callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback), [iterators](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators) **Java** ```java public SnsrSession forEach(String key, SnsrSession.Listener jcb); ``` **Parameters and return value:** **Input parameter:** `key` * [Iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators) key. **Input parameter:** `jcb` * An object that implements the [listener](https://doc.sensory.com/tnl/7.8/api/inference.md#listener) interface. **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. Calls a user function for each iteration over a list. Invokes `jcb` for each iteration over iterator setting `key`. If the callback returns an error (i.e. not [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok)) the iteration loop is terminated early. **Also see these related items:** [callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback), [iterators](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators) ### getters **C/C++** ```c SNSR_API SnsrRC snsrGetDouble(SnsrSession s, const char *key, double *value); SNSR_API SnsrRC snsrGetInt (SnsrSession s, const char *key, int *value); SNSR_API SnsrRC snsrGetStream(SnsrSession s, const char *key, SnsrStream *stream); SNSR_API SnsrRC snsrGetString(SnsrSession s, const char *key, const char **value); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Input parameter:** `key` * A [key](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) that identifies which setting to read. **Output parameter:** `value` * The value of `key`, in the type matching the function name. **Output parameter:** `stream` * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle (`snsrGetStream` only). **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java public double getDouble(String key); public int getInt (String key); public SnsrStream getStream(String key); public String getString(String key); ``` **Parameters and return value:** **Input parameter:** `key` * A [key](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) that identifies which setting to read. **Return value:** * The value of `key`, in the type matching the method name. Read a typed value from a session setting or template slot. | Function | Type | Key realm | Use when | |---------------|----------|----------------------------|---------------------------------------------------------| | `getDouble` | `double` | [setting keys](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) | reading a numeric setting (handles `double` and `int`). | | `getInt` | `int` | [setting keys](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) | reading an integer setting. | | `getStream` | stream | [runtime](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#runtime) / template slot | reading recognition audio or a serialized template slot. | | `getString` | string | [setting keys](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) | reading a textual setting. | - **`getInt`** returns [`INCORRECT_SETTING_TYPE`](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_incorrect_setting_type) if the key holds a `double` value that either includes a fractional part or is too large to fit into a 32-bit `int`. - **`getStream`** retrieves [runtime](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#runtime) streams (such as recognition audio or enrolled phrase spot modules) and models from [task template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) slots; for template slots, the returned stream contains a serialized version of the slot in [CONFIG](https://doc.sensory.com/tnl/7.8/api/inference.md#dataformat) format. It *cannot* be used to read back the stream handles installed via [setStream](https://doc.sensory.com/tnl/7.8/api/inference.md#setters). The returned [stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle is valid only until the next library call on the session — if you need to extend this, [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) the handle and [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) it when no longer useful. - **`getString`** auto-converts `int` and `double` setting values to their string form. The returned C string is valid only until the next library call on the session — same lifetime caveat as above. *(The Java `getString` returns a Java `String` and has no such caveat.)* **Also see these related items:** [set](https://doc.sensory.com/tnl/7.8/api/inference.md#set), [setters](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), [setting keys](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys), [runtime](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#runtime), [0.](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0), [1.](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1) ### load **C/C++** ```c SNSR_API SnsrRC snsrLoad(SnsrSession s, SnsrStream inputStream); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Input parameter:** `inputStream` * Readable [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle that contains a model. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java public SnsrSession load(SnsrStream inputStream) throws java.io.IOException; public SnsrSession load(String fileName) throws java.io.IOException; ``` **Parameters and return value:** **Input parameter:** `inputStream` * Readable [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle that contains a model. **Input parameter:** `fileName` * Path to a model file on disk, e.g. `"model.snsr"` **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. Loads a task model into a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session). Loads a task or configuration settings from a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) into the [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session). The stream data must be in the format produced by [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save). This function retains a reference to `inputStream` on entry and releases it on exit. `load` will open `inputStream`, but will not close it explicitly. [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream)s are closed before deallocation, so `inputStream` would be closed if no other references to it are held. **Also see these related items:** [new](https://doc.sensory.com/tnl/7.8/api/inference.md#new) ### new **C/C++** ```c SNSR_API SnsrRC snsrNew(SnsrSession *s); ``` **Parameters and return value:** **Output parameter:** `s` * A pointer to a memory location that will receive the [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. If `s` is not `NULL`, best practice is to retrieve the detailed error message with [errorDetail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail). **Java** ```java public SnsrSession() {}; ``` **Parameters and return value:** **Return value:** * A new instance of the [SnsrSession](https://doc.sensory.com/tnl/7.8/api/inference.md#session) class. This function creates a new [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle that contains the entire state for a task. **Also see these related items:** [dup](https://doc.sensory.com/tnl/7.8/api/inference.md#dup), [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) ### Details: Implementation details `snsrNew()` is a preprocessor macro that selects one of three function variants depending whether macros `SNSR_OMIT_OSS_COMPONENTS` and `SNSR_USE_SUBSET` are defined. ```c #ifndef SNSR_USE_SUBSET # ifdef SNSR_OMIT_OSS_COMPONENTS # define snsrNew(s) snsrNewOmitOSS((s), SNSR_VERSION) # else # define snsrNew(s) snsrNewIncludeOSS((s), SNSR_VERSION) # endif #else # define snsrNew(s) snsrNewSubset((s), SNSR_VERSION) #endif SNSR_API SnsrRC snsrNewSubset(SnsrSession *s, const char *version); SNSR_API SnsrRC snsrNewIncludeOSS(SnsrSession *s, const char *version); SNSR_API SnsrRC snsrNewOmitOSS(SnsrSession *s, const char *version); ``` ### profile - pre-release **C/C++** ```c SNSR_API SnsrRC snsrProfile(SnsrSession s, SnsrStream out); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Input parameter:** `out` * Writable [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java public SnsrSession profile(SnsrStream out); ``` **Parameters and return value:** **Input parameter:** `out` * Writable [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. Writes a human-readable model inference timing profile to a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Pre-release:** This is an experimental feature. Do not use unless recommended by Sensory. **Also see these related items:** [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-evalc) ### push **C/C++** ```c SNSR_API SnsrRC snsrPush(SnsrSession s, const char *name, const void *data, size_t sizeInBytes); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Input parameter:** `name` * The name of an input stream, such as [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm). **Input parameter:** `data` * Read-only pointer to data, typically 16-bit linear PCM encoded audio in little-endian format. **Input parameter:** `sizeInBytes` * The number of bytes of `data` to process. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java public SnsrSession push(String name, byte[] data); ``` **Parameters and return value:** **Input parameter:** `name` * The name of an input stream, such as [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm). **Input parameter:** `data` * Data to process, typically 16-bit linear PCM encoded audio in little-endian format. **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. Processes data in a session. Adds `data` to the `name` input [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) for [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) `s`, then processes these and other buffered stream data. Invokes [events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) registered in the session and writes to any output streams the model defines. Processing continues until one of these is true: * Everything in `data` is processed. * One of the invoked callbacks returns an error code, which `push` will return. Use [INTERRUPTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [REPEAT](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_repeat), [SKIP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_skip), [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop), or [TIMED_OUT](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_timed_out) to indicate that the operation was stopped on request. * The [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit) timeout is reached. `push` invokes [event](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) callbacks on the thread that it was called on. The processing loop is single-threaded, so it stalls while waiting for user functions to return. If [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit) is used, `push` has to defer processing when the duration limit is reached. In this case, `data` are added to an internal ring buffer. `push` report [NOT_ENOUGH_SPACE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) if no space remains for this deferral. To address such a failure, you could: * Increase the [push-buffer-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-buffer-size). * Increase the [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit). * Use a model with lower CPU requirements. **Also see these related items:** [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run), [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop), [push-buffer-backlog](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-buffer-backlog), [push-buffer-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-buffer-size), [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit) ### rC **C/C++** ```c SNSR_API SnsrRC snsrRC(SnsrSession s); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Return value:** * The current [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) code for `s`. **Java** ```java public SnsrRC rC(); ``` **Parameters and return value:** **Return value:** * The current [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) code for this [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance. Retrieves the session return code. Returns the most recent [return code](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) from session `s`. **Also see these related items:** [clearRC](https://doc.sensory.com/tnl/7.8/api/inference.md#clearrc), [errorDetail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail), [rCMessage](https://doc.sensory.com/tnl/7.8/api/inference.md#rcmessage) ### rCMessage **C/C++** ```c SNSR_API const char * snsrRCMessage(SnsrRC returnCode); ``` **Parameters and return value:** **Input parameter:** `returnCode` * A session or stream [return code](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). **Return value:** * A string describing the return code. The memory pointed to is owned by this library and must not be released. It is not reference-counted. Calling [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) or [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) on it will panic the heap allocator. Describes a return code. Provides a human-readable error message describing `returnCode`. This message should be used for display or logging only. The content of the message is unspecified and system-specific. Do not parse this to determine program flow, use the [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) code instead. If a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle is available, use [errorDetail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail) instead, as this provides additional details. **Also see these related items:** [errorDetail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail) **Java** _Use the [errorDetail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail) method instead._ ### release **C/C++** _The C language binding uses reference counting to manage object lifetimes, see [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) and [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) in the [memory management](https://doc.sensory.com/tnl/7.8/api/heap.md#memory-management) section._ **Java** ```java public void release(); ``` Releases the native library handle encapsulated by the [SnsrSesion](https://doc.sensory.com/tnl/7.8/api/inference.md#session) class. This method releases native handles immediately. Use this to free up resources without having to depend on garbage collection cycle eventually running. *No instance methods must be invoked after calling this method.* **Example:** ```java SnsrSession s = new SnsrSession(); // ... s.release(); s = null; ``` ### require **C/C++** ```c SNSR_API SnsrRC snsrRequire(SnsrSession s, const char *key, const char *value); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Input parameter:** `key` * Setting to validate: [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type), [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version), or [task-type-and-version-list](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type-and-version-list). **Input parameter:** `value` * String to match `key` against. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java public SnsrSession require(String key, String value); ``` **Parameters and return value:** **Input parameter:** `key` * Setting to validate: [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type), [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version), or [task-type-and-version-list](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type-and-version-list). **Input parameter:** `value` * String to match `key` against. **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. Validates task requirements. Checks that the value for the `key`, for the task loaded into the current [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session), matches the specified `value`. **Note:** Using `require` is entirely optional. Use it as a sanity check to verify that the model loaded is of the correct type, and that it has a compatible version. If `key` is [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type), `version` should be one of the task type constants defined in [values](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#values). If `key` is [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version), this function uses [semantic versioning][semver] precedence to determine whether the task version meets the `value` version requirement. If `key` is [task-type-and-version-list](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type-and-version-list), `version` is a list of acceptable [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) and [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version) tuples separated by `;`. Version strings can include range specifiers: * A *range* is composed of one or more *sets*, joined by ` || `. A version matches a *range* iff every *comparator* in at least one of the *sets* is satisfied by the version. * A *set* is a list of *comparators* separated by whitespace. A *set* is satisfied by the _intersection_ of all the *comparators* it includes. * A *comparator* is an *operator* followed by a version. * *operators* include: * `=`, `<`, `<=`, `>`, `>=` : range comparisons. * `~` : `taskVersion >= value && taskVersion < M` where M is the next major version number. * `^` : `taskVersion >= value && taskVersion < M` where M is the next major version number, skipping over zeros from the left. For `taskVersion >= 1.0.0` this is equivalent to the `~` operator. `^0.minor.patch` allows only patch updates, e.g. `^0.1.1` will accept `0.1.2` but not `0.2.0`. * The default behavior when no operator is specified is `^`. **Also see these related items:** [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type), [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version), [task-type-and-version-list](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type-and-version-list) **Example:** **C/C++** ```c snsrRequire(s, SNSR_TASK_TYPE, SNSR_PHRASESPOT); snsrRequire(s, SNSR_TASK_VERSION, "1.0.0"); snsrRequire(s, SNSR_TASK_VERSION, "0.5.0 || 1.0.0"); snsrRequire(s, SNSR_TASK_TYPE_AND_VERSION_LIST, SNSR_PHRASESPOT " ~0.5.0 || 1.0.0;" SNSR_PHRASESPOT_VAD " 1.2.3"); ``` **Java** ```java session.require(Snsr.TASK_TYPE, Snsr.PHRASESPOT); session.require(Snsr.TASK_VERSION, "1.0.0"); session.require(Snsr.TASK_VERSION, "0.5.0 || 1.0.0"); session.require(Snsr.TASK_TYPE_AND_VERSION_LIST, Snsr.PHRASESPOT + " ~0.5.0 || 1.0.0;" + Snsr.PHRASESPOT_VAD + " 1.2.3"); ``` ### reset - since [6.10.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.10.0) **C/C++** ```c SNSR_API SnsrRC snsrReset(SnsrSession s); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java public SnsrSession reset(); ``` **Parameters and return value:** **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. Resets a session to its initial state. This call resets the session error code to [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok), clears the error detail, discards all pending results, clears internal buffers, and resets session time and sample counts to `0`. `reset` is most useful to clear the state of a [template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) model, such as [tpl-spot-vad](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad.md#tpl-spot-vad-type), that was stopped through a callback. **Warning:** Invoking this function in a callback handler will lead to undefined behavior. ### run **C/C++** ```c SNSR_API SnsrRC snsrRun(SnsrSession s); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java public SnsrSession run () throws java.io.IOException; ``` **Parameters and return value:** **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. Processes stream data in a session. Enters the main session processing loop. This function will process data read from input streams, invoke [events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) registered in the session and write to any output streams the model defines. Processing continues until one of these is true: * One of the data streams reach [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof), in which case `run` returns [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end) * One of the invoked callbacks returns an error code, which `push` will return. Use [INTERRUPTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [REPEAT](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_repeat), [SKIP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_skip), [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop), or [TIMED_OUT](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_timed_out) to indicate that the operation was stopped on request. `run` invokes [event](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) callbacks on the thread that it was called on. The processing loop is single-threaded, so it stalls while waiting for user functions to return. `run` will flush the internal recognition pipeline an input stream reaches [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof), unless [auto-flush](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#auto-flush) is set to `0`. **Also see these related items:** [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop) ### save **C/C++** ```c SNSR_API SnsrRC snsrSave(SnsrSession s, SnsrDataFormat format, SnsrStream outputStream); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Input parameter:** `format` * [DataFormat](https://doc.sensory.com/tnl/7.8/api/inference.md#dataformat) controls serialization behavior. **Input parameter:** `outputStream` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) where `save` writes the serialization to. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java public SnsrSession save(SnsrDataFormat format, SnsrStream outputStream); public SnsrSession save(SnsrDataFormat format, String fileName); ``` **Parameters and return value:** **Input parameter:** `format` * [DataFormat](https://doc.sensory.com/tnl/7.8/api/inference.md#dataformat) controls serialization behavior. **Input parameter:** `outputStream` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) where `save` writes the serialization to. **Input parameter:** `fileName` * Path to a file on disk where `save` should write to. **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. Serializes a session to a stream. Saves the configuration or runtime settings of the session to a writable output [stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Also see these related items:** [DataFormat](https://doc.sensory.com/tnl/7.8/api/inference.md#dataformat), [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) ### set **C/C++** ```c SNSR_API SnsrRC snsrSet(SnsrSession s, const char *keyValue); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Input parameter:** `keyValue` * List of setting assignments, `key=value ...`. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java public SnsrSession set(String key, double value); public SnsrSession set(String key, int value); public SnsrSession set(String key, SnsrStream stream); public SnsrSession set(String key, String value); public SnsrSession set(String keyValue); ``` **Parameters and return value:** **Input parameter:** `key` * A [key](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#configuration) that identifies which configuration option to change. **Input parameter:** `value` * New value for `key`. **Input parameter:** `stream` * A [stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Input parameter:** `keyValue` * List of setting assignments, `key=value ...`. **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. Changes session configuration. **C/C++** This utility function parses the `keyValue` string for both [keys](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#configuration) and double, integer, or string values, then updates the session accordingly. Use this to change task configuration from user-supplied configuration strings provided to a command-line application. `keyValue` should be of the form `"key=value ..."`, e.g. `"delay=30"` or `"accuracy=0.5 delete-user=hbg"`. Use double quotes around string values that include whitespace. **Note:** Use [setDouble](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), [setInt](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), and [setString](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) when the key name is known at compile time, as these functions do not incur the `keyValue` string parsing overhead. **Also see these related items:** [setDouble](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), [setInt](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), [setString](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) **Java** The `set(key, value)` variants infer the setting type from the type of the `value` argument. These are equivalent to [setDouble](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), [setInt](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), [setStream](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), and [setString](https://doc.sensory.com/tnl/7.8/api/inference.md#setters). The `set(keyValue)` variant parses the `keyValue` string for both [keys](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) and double, integer, or string values, then updates the session accordingly. Use this to change task configuration from user-supplied configuration strings provided to a command-line application. `keyValue` should be of the form `"key=value ..."`, e.g. `"delay=30"` or `"accuracy=0.5 delete-user=hbg"`. Use double quotes around string values that include whitespace. **Note:** Use `set(key, value)` (or [setDouble](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), [setInt](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), and [setString](https://doc.sensory.com/tnl/7.8/api/inference.md#setters)) when the key name is known at compile time, as these functions do not incur the `keyValue` string parsing overhead. **Also see these related items:** [setDouble](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), [setInt](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), [setStream](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), [setString](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) ### setHandler **C/C++** ```c SNSR_API SnsrRC snsrSetHandler(SnsrSession s, const char *key, SnsrCallback c); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Input parameter:** `key` * A [key](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) that identifies which event this handler is for. **Input parameter:** `c` * A [callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback) instance to invoke when the event specified by `key` occurs, or `NULL` to delete an existing callback for `key`. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. Sets a session callback handler. This sets a function to call when the session raises the event specified by `key`. It replaces the previous handler for `key`. [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) ignores events without handlers. Best practice is to register handlers only for events that you need to take action on. **Also see these related items:** [callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback), [events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events), [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) **Java** ```java public SnsrSession setHandler(String key, SnsrSession.Listener jcb); ``` **Parameters and return value:** **Input parameter:** `key` * A [key](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) that identifies which event this handler is for. **Input parameter:** `jcb` * An object that implements the [Listener](https://doc.sensory.com/tnl/7.8/api/inference.md#listener) interface, or `null` to delete an existing callback for `key`. **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. Sets a session callback handler. This sets a method to call when the session raises the event specified by `key`. It replaces the previous handler for `key`. [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) ignores events without handlers. Best practice is to register handlers only for events that you need to take action on. **Also see these related items:** [listener](https://doc.sensory.com/tnl/7.8/api/inference.md#listener), [events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events), [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) ### setters **C/C++** ```c SNSR_API SnsrRC snsrSetDouble(SnsrSession s, const char *key, double value); SNSR_API SnsrRC snsrSetInt (SnsrSession s, const char *key, int value); SNSR_API SnsrRC snsrSetStream(SnsrSession s, const char *key, SnsrStream stream); SNSR_API SnsrRC snsrSetString(SnsrSession s, const char *key, const char *value); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Input parameter:** `key` * A [key](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#configuration) (`snsrSetDouble`, `snsrSetInt`, `snsrSetString`) or [key](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#runtime) (`snsrSetStream`) that identifies which setting to change. **Input parameter:** `value` * New value for `key`, in the type matching the function name. **Input parameter:** `stream` * A [stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle (`snsrSetStream` only). **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java public SnsrSession setDouble(String key, double value); public SnsrSession setInt (String key, int value); public SnsrSession setStream(String key, SnsrStream stream); public SnsrSession setString(String key, String value); ``` **Parameters and return value:** **Input parameter:** `key` * A [key](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#configuration) (`setDouble`, `setInt`, `setString`) or [key](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#runtime) (`setStream`) that identifies which setting to change. **Input parameter:** `value` * New value for `key`, in the type matching the method name. **Input parameter:** `stream` * A [stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle (`setStream` only). **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. Change a typed session configuration value, or load a model into a template slot. | Function | Type | Key realm | Use when | |---------------|----------|----------------------------|-----------------------------------------------------------| | `setDouble` | `double` | [configuration](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#configuration) | writing a numeric setting (handles `double` and `int`). | | `setInt` | `int` | [configuration](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#configuration) | writing an integer setting. | | `setStream` | stream | [runtime](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#runtime) / template slot | installing audio I/O, or loading a model into a template slot. | | `setString` | string | [configuration](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#configuration) | writing a textual setting. | - **`setDouble`** returns [`INCORRECT_SETTING_TYPE`](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_incorrect_setting_type) (without changing the key) if the target [key](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#configuration) requires an `int` and `value` either includes a fractional part or is too large to fit into a 32-bit `int`. - **`setStream`** has two effects: 1. associates `stream` with the source or sink specified by `key`; 2. if `key` refers to a slot in a [task template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type), loads a model from `stream` into that slot. - **`setString`** auto-coerces values when the target [key](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#configuration) expects a numeric type: it parses `value` into a `double` and then performs the equivalent of [setDouble](https://doc.sensory.com/tnl/7.8/api/inference.md#setters). **Also see these related items:** [set](https://doc.sensory.com/tnl/7.8/api/inference.md#set), [getters](https://doc.sensory.com/tnl/7.8/api/inference.md#getters), [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load), [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), [<-audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-pcm-out), [0.](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0), [1.](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1) ### stop - since [6.20.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.20.0) **C/C++** ```c SNSR_API SnsrRC snsrStop(SnsrSession s); ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java public SnsrSession stop(); ``` **Parameters and return value:** **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. Stops session processing. When used with pull mode audio processing, this function will cause [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) to stop and return [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop). The call to `stop` returns as soon as it has requested the session to stop, it **does not** wait until `run` has returned. It **is** safe to call `stop` from a different thread than the one `run` is executing on. When used with push mode audio processing and [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), this function flushes the session processing pipeline, stops any internal processing threads started for the session, and then returns. If the session detects any [events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) while flushing the pipeline it will invoke the callbacks registered for these before `stop` returns. **Also see these related items:** [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) ## Enumerations [DataFormat](https://doc.sensory.com/tnl/7.8/api/inference.md#dataformat) specifies the [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save) serialization format, and [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) has the complete list of TrulyNatural SDK return codes. ### DataFormat **C/C++** ```c typedef enum { SNSR_FM_{name}, ... } SnsrDataFormat; // Where {name} is from the table below, e.g.: SNSR_FM_CONFIG ``` **Java** ```java public enum SnsrDataFormat { {name}, ... } // Where {name} is from the table below, e.g.: SnsrDataFormat.CONFIG ``` This specifies the [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) serialization format and content. **Also see these related items:** [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save) **`CONFIG`** _(recommended)_ All configuration settings. *This is the most common use case.* **`CONFIG_PRUNED`** Prune unused configuration settings, then serialize all remaining ones. An example of unused configuration settings are wake word operating points other than the currently selected [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point). **`SUBSET_INIT`** Custom initialization code for a model subset. Limited initialization reduces overall executable code size by eliding unused modules. To enable, add the generated custom code to the build, and recompile with `-DSNSR_USE_SUBSET`. **`RUNTIME`** Runtime settings, such as enrollments, only. **`SOURCE`** All configuration settings, as C source code run from ROM. Optimized to reduce RAM overhead by running from code space. This code targets the same version of the TrulyNatural SDK used to generate it. If you upgrade the SDK, also update any previously generated C source files. **Also see these related items:** [tag-identifier](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#tag-identifier), [model-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#model-name) **`SOURCE_RAM`** All configuration settings, as C source code loaded into RAM. Optimized for execution speed by loading model data into RAM. This code targets the same version of the TrulyNatural SDK used to generate it. If you upgrade the SDK, also update any previously generated C source files. **Also see these related items:** [tag-identifier](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#tag-identifier), [model-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#model-name) **`SOURCE_PRUNED`** Prune unused configuration settings, serialize remainder as C source code. This code targets the same version of the TrulyNatural SDK used to generate it. If you upgrade the SDK, also update any previously generated C source files. An example of unused configuration settings are wake word operating points other than the currently selected [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point). **Also see these related items:** [tag-identifier](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#tag-identifier), [model-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#model-name) ### RC **C/C++** ```c typedef enum { SNSR_RC_{name}, ... } SnsrRC; // Where {name} is from the table below, e.g.: SNSR_RC_OK ``` **Java** ```java public enum SnsrRC { {name}, ... } // Where {name} is from the table below, e.g.: SnsrRC.OK ``` SDK return code. [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) indicates success, anything else is a failure. Use [errorDetail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail) to obtain a more detailed description of what went wrong. **Also see these related items:** [errorDetail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail), [rCMessage](https://doc.sensory.com/tnl/7.8/api/inference.md#rcmessage) **`OK`** Operation completed successfully. **`EOF`** Unexpected end-of-stream encountered. **`ERROR`** Operation failed. **`NOT_OPEN`** Stream is not open. **`NOT_FOUND`** Resource not found. **`NO_MEMORY`** Out of heap memory. **`WRONG_MODE`** Incorrect stream mode (read or write). **`INTERRUPTED`** Interrupted. **`INVALID_ARG`** Invalid argument. **`INVALID_MODE`** Invalid mode. **`CANNOT_REOPEN`** Cannot re-open this stream. **`INVALID_HANDLE`** The stream handle is invalid. **`NOT_IMPLEMENTED`** Function is not implemented for this stream type. **`DELIM_NOT_FOUND`** Delimiter character not encountered. **`FORMAT_NOT_SUPPORTED`** Stream format is not supported. **`BUFFER_OVERRUN`** Buffer overrun, stream not read from in time **`BUFFER_UNDERRUN`** Buffer underrun, stream not written to in time. **`RESERVED_A`** Invalid return code. **Not used**. **`ARG_OUT_OF_RANGE`** Argument value is not in the valid range. **`CHANNEL_EXISTS`** A channel with this name already exists in the bin. **`CHANNEL_NOT_BUFFERED`** This channel is not backed by a circular buffer. **`CHANNEL_NOT_FOUND`** Channel not found. **`CHANNELS_NOT_COMPATIBLE`** Source and destination channel types are not compatible. **`CONFIGURATION_INCONSISTENT`** Element settings are inconsistent. **`CONFIGURATION_MISSING`** Element configuration is missing. **`CONNECTION_NOT_FOUND`** Connection not found. **`DST_CHANNEL_NOT_FOUND`** Destination channel not found. **`DST_ELEMENT_NOT_IN_BIN`** Destination element is not in this bin. **`DST_PORT_IN_USE`** The destination port is already connected. **`ELEMENT_ID_NOT_KNOWN`** Element ID is not known. The model either requires an updated SDK library, or a build with the default snsrNew() initialization. **Also see these related items:** [model:ids](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#modelids), [SUBSET_INIT](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_subset_init) **`ELEMENT_INIT_FAILED`** Element initialization failed. **`ELEMENT_INIT_INCOMPLETE`** Element initialization is incomplete. **`ELEMENT_IS_NOT_A_BIN`** Element is not a bin, function is not available. **`ELEMENT_NOT_IN_BIN`** Element is not in this bin. **`ELEMENT_NOT_ROOT_BIN`** Element is not the root bin, function is not available. **`ELEMENT_REGISTRATION_FAILED`** Element registration failed. **`INCORRECT_SETTING_TYPE`** Setting is not of the correct type. **`LICENSE_NOT_VALID`** License validation failed. **`LICENSE_LIMIT_EXCEEDED`** License runtime duration or recognition limit exceeded. **`ITERATION_LIMIT`** Push iteration limit exceeded. **`ELEMENT_API_VIOLATION`** Element API processing check failed. **`NAME_NOT_UNIQUE`** Name is not unique for this bin. **`NOT_ENOUGH_SPACE`** Buffer does not have enough free space. **`NOT_INITIALIZED`** Element has not been initialized. **`PUSH_FAILED`** Push failed. **`PUSH_DURATION_EXCEEDED`** Push duration limit exceeded. **`REPEAT`** Repeated by callback. **`SETTING_FAILED`** Setting could not be applied. **`SETTING_IS_READ_ONLY`** Setting is read-only. **`SETTING_NOT_AVAILABLE`** Setting is not available in this context. **`SETTING_NOT_FOUND`** Setting not found for this element. **`SKIP`** Skipped by callback. **`SRC_CHANNEL_NOT_FOUND`** Source channel not found. **`SRC_ELEMENT_NOT_IN_BIN`** Source element is not in this bin. **`SRC_PORT_IN_USE`** The source port is already connected. **`STOP`** Stopped by callback. **`STREAM`** Stream operation failed. **`STREAM_END`** End-of-stream reached. **`UNKNOWN_OBJECT_TYPE`** Unknown configuration object type. **`VALUE_NOT_SET`** Setting has no configured value. **`CODE_MODEL_TOO_OLD`** SnsrCodeModel task is for an older SDK release. Re-convert from the source *.snsr file for this release. **`RESERVED_B`** Invalid return code. **Not used**. **`NO_MODEL`** No task model data found. You'll see this error if you try to read or modify a [setting](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) before you've loaded a model into a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session). **`REQUIRE_MISMATCH`** Task value does not match requirement. **`VERSION_MISMATCH`** Task version does not match the requirement. **`LIBRARY_HEADER`** The header file version does not match that of the library. [VERSION](https://doc.sensory.com/tnl/7.8/api/constants.md#version) in `snsr.h` does not match the version the library archive was compiled with. Use the `snsr.h` shipped with the TrulyNatural 7.8.0-pre.0+682.g276c2541e9 SDK distribution. **`LIBRARY_TOO_OLD`** TrulyNatural library is too old. Loading of a new task failed as it requires features that are not available in this release of the library. Please contact Sensory for assistance. **Also see these related items:** [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load), [VERSION](https://doc.sensory.com/tnl/7.8/api/constants.md#version) **`ALLOCATOR_EXISTS`** A heap allocator is already in use. You must call `snsrConfig(SNSR_CONFIG_HEAP_SEGMENT, ...)` before any other library calls. **`NO_FUNC`** A required implementation function is `NULL`. **`NOT_SUPPORTED`** The feature is not supported by the current library configuration. For example: Attempting to use [ALLOC_ADD_POOL](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc_add_pool) with a custom allocator that does not support multiple backing store memory pools. **`TIMED_OUT`** Operation timed out. **`LICENSE_OVERRIDE_NOT_ENABLED`** License key override is not enabled by the library license key. **`LICENSE_OVERRIDE_NOT_SUPPORTED`** License key override is not supported on this platform. **`LICENSE_OVERRIDE_NOT_VALID`** License override key does not exist or is not valid. **C/C++** ```c ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java ``` **Parameters and return value:** **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. --> [semver]: http://semver.org/ "Semantic versioning specification" *[API]: Application Programming Interface *[iff]: if, and only if *[RAM]: Random Access Memory *[ROM]: Read-Only Memory, typically nonvolatile flash memory *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[VAD]: Voice Activity Detector --- source_path: "api/io.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/io/" --- # Input and output The [inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference) [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) uses [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instances for all input and output. This includes model loading, audio input and output, binary data, and large sections of text. Most-used [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) APIs: | API | Summary | |-----|---------| | [fromFileName](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename) | Open a file path for read, write, or append. | | [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory) | Read or write a fixed memory buffer. | | [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) | Capture live audio from the platform microphone. | | [fromAudioStream](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiostream) | Convert audio format on an existing source stream. | | [fromBuffer](https://doc.sensory.com/tnl/7.8/api/io.md#frombuffer) | Ring buffer for streaming audio with bounded history. | | [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) | Custom source or sink implemented with callbacks. | | [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open) | Open a stream before [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) or [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write). | | [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) | Read bytes from an open stream (blocks until data or EOF). | | [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) | Write bytes to an open stream. | | [copy](https://doc.sensory.com/tnl/7.8/api/io.md#stream-copy) | Copy all data from one stream to another. | Stream error state clears on the next operation; use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to inspect. Checked `IOException`s on Java stream I/O are summarized in [API overview](https://doc.sensory.com/tnl/7.8/api/overview.md#api-overview). See [constructors](https://doc.sensory.com/tnl/7.8/api/io.md#constructors) and [operations](https://doc.sensory.com/tnl/7.8/api/io.md#operations) for the full lists. ## Stream **C/C++** ```c typedef struct SnsrStream_ *SnsrStream; ``` **Java** ```java public class SnsrStream {} ``` `SnsrStream` is the TrulyNatural SDK API input and output type. This `SnsrStream` abstraction decouples the inference type from the actual data sources and sinks. This, for example, allows models to load and run even when a file system isn't available. The [constructors](https://doc.sensory.com/tnl/7.8/api/io.md#constructors) section describes all of the stream implementations (adapters, wrappers) included in this SDK. Stream instances support the same set of [operations](https://doc.sensory.com/tnl/7.8/api/io.md#operations). **C/C++** `SnsrStream` handles are [reference-counted](https://doc.sensory.com/tnl/7.8/api/heap.md#reference-counting), with lifetimes managed by [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) and [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release). **Java** Best practice is to [release](https://doc.sensory.com/tnl/7.8/api/io.md#stream-release) a stream object before allowing garbage collection to reclaim the object memory. This will free all encapsulated resources immediately. **Note:** The current implementation does not do any thread-level locking. Threaded access to stream handles must be protected by explicit synchronization calls. ### Constructors This section describes the predefined stream constructors. We provide stream implementations for [files](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename), [file handles](https://doc.sensory.com/tnl/7.8/api/io.md#fromfile), [live audio sources](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice), [circular buffers](https://doc.sensory.com/tnl/7.8/api/io.md#frombuffer), [models compiled to code](https://doc.sensory.com/tnl/7.8/api/io.md#fromcode), [memory segments](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory), [strings](https://doc.sensory.com/tnl/7.8/api/io.md#fromstring), and [user-defined data](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) sources or sinks. This library also includes stream transformations for [audio format conversion](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiostream), stream [concatenation](https://doc.sensory.com/tnl/7.8/api/io.md#fromstreams), and [limiting the extent](https://doc.sensory.com/tnl/7.8/api/io.md#fromopenstream) of [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) or [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) operations. **C/C++** **Note:** Functions in this group that take `SnsrStream` arguments [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) these handles and [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) them when they are no longer used. A `SnsrStream` handle with a zero reference count used as an argument will therefore be deallocated when it is no longer needed. Be sure to call [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) on handles that need to survive these function invocations. #### fromAsset **C/C++** ```c SNSR_API SnsrStream snsrStreamFromAsset(AAssetManager *mgr, const char *filename); ``` **Parameters and return value:** **Input parameter:** `mgr` * Android [AAssetManager][] object. **Input parameter:** `filename` * Path to the asset, relative to the `assets/` directory. Creates a new read-only [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from a compressed Android asset. `filename` is relative to `assets/` and must not include this as part of the name. **Note:** This function is available in C TrulyNatural SDK on Android only. Contact [Sensory][] if you need access to these libraries for Android. **Also see these related items:** [fromFileName](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename) **Java** On Android, [fromFileName](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename) includes support for reading files from `assets/`. #### fromAudioDevice **C/C++** ```c SNSR_API SnsrStream snsrStreamFromAudioDevice(SnsrStreamAudioFormat format, ...); ``` **Parameters and return value:** **Input parameter:** `format` * [StreamAudioFormat](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) format specifier, determines additional arguments. **Input parameter:** `...` * The specific additional arguments required depend on the value of `format`. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Streams live audio from an audio capture device. Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) attached to the specified audio device. This supports audio capture with [ALSA][] on Linux, with [Audio Queue Services][] on macOS and iOS, and with the [Windows Multimedia Extensions][] Wave API on Windows. [DEFAULT](https://doc.sensory.com/tnl/7.8/api/io.md#st_af_default) sets the default capture device with the format (16-bit little-endian LPCM) and sample rate (16 kHz) required by most TrulyNatural SDK recognizers. This is the recommended format specifier. **Example:** ```c // Use a specific ALSA device, rather than the default. // The "plughw" device typically includes sample rate conversion, // use this if the hardware does not support sampling at 16 kHz. SnsrStream a = snsrStreamFromAudioDevice(SNSR_ST_AF_DEVICE, "plughw:1,0"); ``` **Also see these related items:** [ALSA][], [Audio Queue Services][], [Windows Multimedia Extensions][] **Java** ```java static SnsrStream fromAudioDevice(); static SnsrStream fromAudioDevice(int device, int sampleRate); // (1)! static SnsrStream fromAudioDevice(int sampleRate); ``` 1. Available on Android only. **Parameters and return value:** **Input parameter:** `device` * Android audio [source specifier][MediaRecorder.AudioSource]. **Input parameter:** `sampleRate` * Audio capture sample rate. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Streams live audio from an audio capture device. `#!java static SnsrStream fromAudioDevice()` creates a new stream attached to the default audio recording device, with the [DEFAULT](https://doc.sensory.com/tnl/7.8/api/io.md#st_af_default) encoding and sample rate. `#!java static SnsrStream fromAudioDevice(int device, int sampleRate)` creates a new stream attached to the specified [MediaRecorder.AudioSource][] and sample rate. _This method is available on Android devices only._ `#!java static SnsrStream fromAudioDevice(int sampleRate)` creates a new stream attached to the default audio recording device at the sample rate specified. **Also see these related items:** [AudioRecord][], [Java Audio][] #### fromAudioFile **C/C++** ```c SNSR_API SnsrStream snsrStreamFromAudioFile(const char *filename, const char *mode, SnsrStreamAudioFormat format, ...); ``` **Parameters and return value:** **Input parameter:** `filename` * The name of a file to open. **Input parameter:** `mode` * `r` to open for reading, or `w` for writing. **Input parameter:** `format` * [StreamAudioFormat](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) audio format. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Java** ```java static SnsrStream fromAudioFile(String filename, String mode); ``` **Parameters and return value:** **Input parameter:** `filename` * The name of a file to open. **Input parameter:** `mode` * `r` to open for reading, or `w` for writing. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance. Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from a [RIFF WAV] audio file. This is equivalent to the code snippet below, with the difference that the RIFF header is updated after each write to the stream. **C/C++** ```c SnsrStream s; s = snsrStreamFromAudioStream(snsrStreamFromFileName(filename, mode), format); ``` **Java** ```java SnsrStream s; s = SnsrStream.fromAudioStream(SnsrStream.fromFileName(filename, mode), SnsrStreamAudioFormat.DEFAULT); ``` Only a subset of the [fopen()][] modes are supported: - `r` for read-only access. - `w` for write-only access, truncating the file to zero on open. This stream type supports re-opening. The behavior follows that of [fopen()][] with the given access mode. **Also see these related items:** [fromAudioStream](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiostream), [fromFileName](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename) #### fromAudioStream **C/C++** ```c SNSR_API SnsrStream snsrStreamFromAudioStream(SnsrStream a, SnsrStreamAudioFormat format, ...); ``` **Parameters and return value:** **Input parameter:** `a` * Source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Input parameter:** `format` * [StreamAudioFormat](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) audio format. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Java** ```java static SnsrStream fromAudioStream(SnsrStream a, SnsrStreamAudioFormat format); ``` **Parameters and return value:** **Input parameter:** `a` * Source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Input parameter:** `format` * [StreamAudioFormat](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) audio format. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Converts stream audio format. Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) on an existing one. The new stream produces audio in `format`, converting as needed. This implementation reads the audio format header in the source stream upon opening. If this is a known, but unsupported format, `fromAudioStream` will report an error. If the format isn't known, it assumes that the data are headerless little-endian 16-bit LPCM audio samples. _The current implementation supports the 16-bit LPCM RIFF WAVE format, sampled at 16 kHz, for a single channel only. The `format` parameter must be set to [DEFAULT](https://doc.sensory.com/tnl/7.8/api/io.md#st_af_default)._ **Note:** When this stream type is used for output, all stream data will be buffered in memory until the stream is closed. The audio header and the data will then be written to the encapsulated stream. If the final destination is a file on disk, use [fromAudioFile](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiofile) instead. **Also see these related items:** [fromAudioFile](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiofile) #### fromBuffer **C/C++** ```c SNSR_API SnsrStream snsrStreamFromBuffer(size_t initialSizeInBytes, size_t maxSizeInBytes); ``` **Parameters and return value:** **Input parameter:** `initialSizeInBytes` * The minimum size of the allocated ring buffer. **Input parameter:** `maxSizeInBytes` * The limit the ring buffer is allowed to expand to. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Java** ```java static SnsrStream fromBuffer(long initialSizeInBytes, long maxSizeInBytes); ``` **Parameters and return value:** **Input parameter:** `initialSizeInBytes` * The minimum size of the allocated ring buffer. **Input parameter:** `maxSizeInBytes` * The limit the ring buffer is allowed to expand to. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) on a ring buffer with FIFO semantics. The initial buffer will be large enough to hold `initialSizeInBytes` bytes, and will dynamically grow up to `maxSizeInBytes`. If this ring buffer cannot be expanded when needed, [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) will set the [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof) condition on the stream. This stream type does not support re-opening. **Note:** Calls to [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) on streams of this type never block. `read` returns [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof) if the buffer runs empty. #### fromCode **C/C++** ```c // Opaque type used for task models converted to C code. typedef const struct SnsrCodeModel_ *SnsrCodeModel; SNSR_API SnsrStream snsrStreamFromCode(SnsrCodeModel identifier); ``` **Parameters and return value:** **Input parameter:** `identifier` * `SnsrCodeModel` handle. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) on a model compiled to code. The `SnsrCodeModel` handle is an identifier loaded from an object file, compiled from C code generated by a call to [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save) with the [SOURCE](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source) or [SOURCE_RAM](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source_ram) format types. These data are typically loaded into the read-only `TEXT` (code) segment. Use this on platforms where the `TEXT` segment is read from ROM to reduce the amount of RAM a model needs to run. **Warning:** You must compile the generated model code with the same alignment and `struct` packing requirements that the TrulyNatural SDK library was built with. Most platforms use the toolchain defaults. _(since [7.8.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.8.0))_ If you compile the model code with an incompatible alignment [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) will fail and report a [STREAM](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) error with [detail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail): `"SnsrCodeModel compiled with incompatible -fpack-struct alignment"`. **Example:** ```c extern SnsrCodeModel snsrmodel; SnsrSession s; snsrNew(&s); snsrLoad(s, snsrStreamFromCode(snsrmodel)); ``` **Also see these related items:** [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save), [SOURCE](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source), [SOURCE_RAM](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source_ram), [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) **Java** _The Java language binding does support models converted to code._ #### fromFILE **C/C++** ```c SNSR_API SnsrStream snsrStreamFromFILE(FILE *handle, SnsrStreamMode mode); ``` **Parameters and return value:** **Input parameter:** `handle` * A standard library `FILE *`, typically `stdout` or `stderr`. **Input parameter:** `mode` * [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode), open for reading or writing, but not both. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Creates a new `SnsrStream` from on a `` `FILE *` handle. Calls to [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-close) on this handle will not close the encapsulated `FILE *`. This stream type does not support re-opening. **Example:** ```c SnsrStream out = snsrStreamFromFILE(stderr, SNSR_ST_MODE_WRITE); snsrStreamOpen(out); snsrStreamPrint(out, "hello world\n"); snsrRelease(out); ``` **Also see these related items:** [fromFileName](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename) **Java** _The Java language binding does support `FILE *` handles._ #### fromFileName **C/C++** ```c SNSR_API SnsrStream snsrStreamFromFileName(const char *filename, const char *mode); ``` **Parameters and return value:** **Input parameter:** `filename` * The name of a file to open. **Input parameter:** `mode` * `r`, `w`, or `a` followed by an optional `b` or `t`. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Java** ```java static SnsrStream fromFileName(String filename, String mode); ``` **Parameters and return value:** **Input parameter:** `filename` * The name of a file to open. **Input parameter:** `mode` * `r`, `w`, or `a` followed by an optional `b` or `t`. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance. Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from a file on disk. Only a subset of the [fopen()][] modes are supported: - `r` for read-only access. - `w` for write-only access, truncating the file to zero on open. - `a` for write-only append access. `mode` supports an optional second character: - `b` for binary mode. This is the default if `mode` contains just one character. - `t` for text mode. On Windows this translates line-endings between `\n` and `\r\n`. This stream type supports re-opening. The behavior follows that of [fopen()][] with the given access mode. **Java** **Note:** On Android, `SnsrStream.fromFileName()` includes support for reading from the the compressed application `assets/` directory. #### fromMemory **C/C++** ```c SNSR_API SnsrStream snsrStreamFromMemory(void *buffer, size_t bufferSize, SnsrStreamMode mode); ``` **Parameters and return value:** **Input-output parameter:** `buffer` * Pointer to a memory segment. **Input parameter:** `bufferSize` * The size of `buffer` in bytes. **Input parameter:** `mode` * [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode), to open for reading or writing, but not both. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from a segment of memory. [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) operations are limited to the first `bufferSize` bytes of the segment starting at `buffer`. This stream type does not support re-opening. **Example:** ```c char *data = malloc(1000); SnsrStream b = snsrStreamFromMemory(data, 1000, SNSR_ST_MODE_WRITE); snsrStreamOpen(b); snsrStreamPrint(b, "hello world, data=%p\n", data); snsrRelease(b); printf("wrote: %s\n", data); free(data); ``` **Also see these related items:** [fromString](https://doc.sensory.com/tnl/7.8/api/io.md#fromstring) **Java** ```java static SnsrStream fromMemory(byte[] store, SnsrStreamMode mode); ``` **Parameters and return value:** **Input-output parameter:** `store` * Data made available to the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Input parameter:** `mode` * [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode), to open for reading or writing, but not both. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance. Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from a segment of memory. This stream type does not support re-opening. **Note:** Changes written through the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) API will only be visible in `store` _after_ the stream instance is [released](https://doc.sensory.com/tnl/7.8/api/io.md#stream-release). Read behavior is undefined if `store` is modified after the `stream` is created. **Also see these related items:** [fromString](https://doc.sensory.com/tnl/7.8/api/io.md#fromstring) #### fromOpenStream **C/C++** ```c SNSR_API SnsrStream snsrStreamFromOpenStream(SnsrStream source, size_t sizeInBytes); ``` **Parameters and return value:** **Input parameter:** `source` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance. **Input parameter:** `sizeInBytes` * New stream read or write limit. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Java** ```java static SnsrStream fromOpenStream(SnsrStream source, long sizeInBytes); ``` **Parameters and return value:** **Input parameter:** `source` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance. **Input parameter:** `sizeInBytes` * New stream read or write limit. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from an existing, open stream. The new stream mode (read or write) matches that of the `source` stream. Read and write operations are passed through to the `source` stream, but the number of bytes read or written is limited to `sizeInBytes`. Input and output operations will set the stream status to [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof) when this limit is reached. Closing this stream will not close `source`. #### fromProvider **C/C++** ```c SNSR_API SnsrStream snsrStream_alloc(SnsrStream_Vmt *def, void *data, int readable, int writable); #define snsrStreamFromProvider(p, d, r, w) snsrStream_alloc(p, d, r, w) ``` **Parameters and return value:** **Input parameter:** `def` * Table of [function pointers](https://doc.sensory.com/tnl/7.8/api/io.md#provider) that define the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) type. **Input parameter:** `data` * User pointer for stream context. **Input parameter:** `readable` * `1` if the stream supports reading, `0` if not. **Input parameter:** `writable` * `1` if the stream supports writing, `0` if not. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Creates a new custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). The `def` [virtual method table](https://doc.sensory.com/tnl/7.8/api/io.md#provider) defines the behavior of the new stream. `data` is an arbitrary pointer that can be retrieved from the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle with [getData](https://doc.sensory.com/tnl/7.8/api/io.md#stream-getData). Use this to hold data specific to the instance. **Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) **Java** ```java static SnsrStream fromProvider(SnsrStream.Provider custom); static SnsrStream fromProvider(SnsrStream.Provider custom, SnsrStreamMode mode); ``` **Parameters and return value:** **Input parameter:** `custom` * An object that implements the [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) interface. **Input parameter:** `mode` * [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode), open for reading or writing, but not both. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Creates a new custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instance. `#!java static SnsrStream fromProvider(SnsrStream.Provider custom)` creates a new stream that supports both reading and writing. `#!java static SnsrStream fromProvider(SnsrStream.Provider custom, SnsrStreamMode mode)` creates a new stream that supports either reading or writing, but not both. #### fromStreams **C/C++** ```c SNSR_API SnsrStream snsrStreamFromStreams(SnsrStream a, SnsrStream b); ``` **Parameters and return value:** **Input parameter:** `a` * First source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Input parameter:** `b` * Second source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Java** ```java static SnsrStream fromStreams(SnsrStream a, SnsrStream b); ``` **Parameters and return value:** **Input parameter:** `a` * First source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Input parameter:** `b` * Second source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Creates a new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) by concatenating two streams. Streams `a` and `b` will be each be opened exactly once. These should be unopened ([getMeta](https://doc.sensory.com/tnl/7.8/api/io.md#stream-getMeta) for [OPEN_COUNT](https://doc.sensory.com/tnl/7.8/api/io.md#streammeta) must be `0`) when `fromStreams` is called. The new stream will read from (or write to) stream `a` until end-of-stream is reached, then switch to stream `b` until that is exhausted, at which point [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) or [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) returns [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof). Streams `a` and `b` must have identical modes. If one stream was created for reading, and the other for writing, this function will set the error code to [WRONG_MODE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). Closing this stream will close the current source stream. The next open call will open the next source stream. When no further source streams remain [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open) returns [CANNOT_REOPEN](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). #### fromString **C/C++** ```c SNSR_API SnsrStream snsrStreamFromString(const char *store); ``` **Parameters and return value:** **Input parameter:** `store` * Data made available to the new stream. Terminated with `\0`. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Creates a new read-only [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from string data. Equivalent to: `#!c snsrStreamFromMemory(store, strlen(store), SNSR_ST_MODE_READ);` This stream type does not support re-opening. **Also see these related items:** [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory) **Java** ```java static SnsrStream fromString(String store); ``` **Parameters and return value:** **Input parameter:** `store` * Data made available to the new stream. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Creates a new read-only [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) from `String` data. **Note:** [Read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) behavior is undefined if `store` is modified after calling `SnsrStream.fromString(store)`. **Also see these related items:** [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory) #### raise **C/C++** ```c typedef SnsrRC (*SnsrStreamEvent)(SnsrStream s, void *data); typedef void (*SnsrDataRelease)(const void *data); SNSR_API SnsrStream snsrStreamRaise(SnsrStreamEvent e, SnsrDataRelease r, void *data); ``` **Parameters and return value:** **Input parameter:** `e` * Function to call when this stream is opened. Must not be `NULL`. **Input parameter:** `r` * A function that releases `data` when this stream is deallocated. Use `NULL` if no clean-up is required. **Input parameter:** `data` * User data pointer, for context. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Inserts an event marker into a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). Use this stream type with [fromStreams](https://doc.sensory.com/tnl/7.8/api/io.md#fromstreams) to embed events in a stream. Creates a new stream that is readable, but provides no data. Any [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) or [skip](https://doc.sensory.com/tnl/7.8/api/io.md#stream-skip) operation will immediately return [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof). Calls `#!c e(b, data)` when this stream is opened. This function should return [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) unless it encounters an error. Calls `#!c r(data)` when this stream is released, unless `r == NULL`. This function should release the `data` handle. **Also see these related items:** [fromStreams](https://doc.sensory.com/tnl/7.8/api/io.md#fromstreams) **Java** ```java public interface Raise { public static final long OK = 0; public static final long EOF = -1; public static final long INTERRUPTED = -2; public static final long INVALID_ARG = -3; public static final long NOT_IMPLEMENTED = -4; public static final long ERROR = -5; public static final long NOT_OPEN = -6; public long onOpen(); } public static SnsrStream raise(SnsrStream.Raise jevent); ``` **Parameters and return value:** **Input parameter:** `jevent` * An object that implements the `SnsrStream.Raise` interface. **Return value:** * A new [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Inserts an event marker into a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). Use this stream type with [fromStreams](https://doc.sensory.com/tnl/7.8/api/io.md#fromstreams) to embed events in a stream. Creates a new stream that is readable, but provides no data. Any [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) or [skip](https://doc.sensory.com/tnl/7.8/api/io.md#stream-skip) operation will immediately return [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof). Calls the `#!java long onOpen()` interface method when this stream is opened. This method should return `Raise.OK` unless it encounters an error. **Also see these related items:** [fromStreams](https://doc.sensory.com/tnl/7.8/api/io.md#fromstreams) ### Operations These functions or methods implement basic [stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) operations, such as [opening](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open), [reading](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read), [writing](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write), and [closing](https://doc.sensory.com/tnl/7.8/api/io.md#stream-close). Utility functions [print](https://doc.sensory.com/tnl/7.8/api/io.md#stream-print) formatted data to a stream, and [inspect stream state](https://doc.sensory.com/tnl/7.8/api/io.md#stream-getMeta). The [error state](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) of a [stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle persists only until the next operation on the stream. These functions do not change the stream handle reference counts. They are therefore safe to use on handles where the reference count is zero. #### atEnd **C/C++** ```c SNSR_API int snsrStreamAtEnd(SnsrStream b); ``` **Parameters and return value:** **Input parameter:** `b` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Return value:** * A boolean value, `1` if at the end of the stream, `0` if not. **Java** ```java public int atEnd(); ``` **Parameters and return value:** **Return value:** * A boolean value, `1` if at the end of the stream, `0` if not. Reports stream end status. Returns `1` if the stream has reached its end, equivalent to [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) `==` [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof). Follows Unix semantics: - The end-of-stream indicator is only valid after a read attempt. - A read on stream `b` could very well return `0`, even if `atEnd` returned `0` just before attempting the read. **Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) #### close **C/C++** ```c SNSR_API SnsrRC snsrStreamClose(SnsrStream b); ``` **Parameters and return value:** **Input parameter:** `b` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java SnsrRC close(); ``` **Parameters and return value:** **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. Closes an open stream. Flushes any remaining buffered output and discards any remaining buffered input. This does not destroy the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) data structure, use [release](https://doc.sensory.com/tnl/7.8/api/io.md#stream-release) to do so. Closing a stream that is not open is _not_ an error. Streams that are still open when they're released are explicitly closed before the data structure is torn down. #### copy **C/C++** ```c SNSR_API size_t snsrStreamCopy(SnsrStream dst, SnsrStream src, size_t sizeInBytes); ``` **Parameters and return value:** **Input parameter:** `dst` * Destination [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Input parameter:** `src` * Source `Stream`. **Input parameter:** `sizeInBytes` * The number of bytes to copy from `src` to `dst`. **Return value:** * The number of bytes written to `dst`. Copies from [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). Ensures that both streams are open, copies `sizeInBytes` bytes from `src` to `dst`, then returns the number of bytes successfully written to `dst`. If an error occurred (including an end-of-stream condition on either `dst` or `src`) the return value will be less than `sizeInBytes`. This function duplicates errors that occur in `src` to `dst`. Use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to inspect these. **Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) **Java** ```java long copy(SnsrStream src) throws java.io.IOException; long copy(SnsrStream src, long sizeInBytes) throws java.io.IOException; ``` **Parameters and return value:** **Input parameter:** `src` * Source [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Input parameter:** `sizeInBytes` * The number of bytes to copy from `src` into this stream. **Return value:** * The number of bytes copied to this `Stream` instance. Copies from [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). Ensures that both streams are open, copies either `sizeInBytes` bytes, or all available data if `sizeInBytes` isn't specified, from `src` to this stream, then returns the number of bytes successfully written. If an error occurred (including an end-of-stream condition on either `dst` or `src`) the return value will be less than `sizeInBytes`. These methods duplicate errors that occur in `src` to `dst`; use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to inspect these. **Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) #### errorDetail **C/C++** ```c SNSR_API const char * snsrStreamErrorDetail(SnsrStream b); ``` **Parameters and return value:** **Input parameter:** `b` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Return value:** * A detailed message describing the most recent reason for failure in `b`. The memory pointed to is owned by this library and must not be released. It is not reference-counted. This pointer remains valid only until the next API call on `b`. **Java** ```java String errorDetail(); ``` **Parameters and return value:** **Return value:** * A detailed message describing the most recent reason for failure on this [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). Retrieves a detailed stream error message. This human-readable error message containing the reason for failure. Use for display or logging only, as the content of the message is unspecified and system-specific. Do not parse this to determine program flow, use the [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) return code instead. #### getDelim **C/C++** ```c SNSR_API size_t snsrStreamGetDelim(SnsrStream b, void *buffer, size_t bufferSize, int delim); ``` **Parameters and return value:** **Input parameter:** `b` * Input stream. **Output parameter:** `buffer` * Destination buffer. **Input parameter:** `bufferSize` * Size of `buffer` in bytes. **Input parameter:** `delim` * delimiter character to search for. **Return value:** * The number of characters read and placed into `buffer`. Reads one line from a stream. Reads a line from stream `b`, delimited by the character `delim`, into `buffer`. This is similar to [`getdelim()`][getdelim], except that it operates on [stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) and does not allocate memory for the destination buffer. `getDelim` ensures that `b` is open, reads up to `bufferSize - 1` bytes from `b` into `buffer`, stops when `delim` has been read (`buffer` will include `delim`). It terminates the string in `buffer` with `\0` and returns the number of characters read (not including the terminating `\0`). If the delimiter is not found after reading `bufferSize - 1` bytes, the error code in `b` is set to [DELIM_NOT_FOUND](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). `buffer` must not be `NULL` and `bufferSize` must be `>= 2`. `buffer` will contain all characters read and will be terminated with `\0`, even if an error occurs. **Java** ```java long getDelim(byte[] buffer, int delim) throws java.io.IOException; ``` **Parameters and return value:** **Output parameter:** `buffer` * Destination buffer, must be at least two bytes long. **Input parameter:** `delim` * delimiter character to search for. **Return value:** * The number of characters read and placed into `buffer`. Reads one line from a stream. Reads a line from stream `b`, delimited by the character `delim`, into `buffer`. This is similar to [`getdelim()`][getdelim], except that it operates on [stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) and does not allocate memory for the destination buffer. `getDelim` ensures that `b` is open, reads up to `buffer.length - 1` bytes from `b` into `buffer`, stops when `delim` has been read (`buffer` will include `delim`). It terminates the string in `buffer` with `\0` and returns the number of characters read (not including the terminating `\0`). If the delimiter is not found after reading `buffer.length - 1` bytes, the error code in `b` is set to [DELIM_NOT_FOUND](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). `buffer` must not be `null` and `buffer.length` must be `>= 2`. `buffer` will contain all characters read and will be terminated with `\0`, even if an error occurs. #### getMeta **C/C++** ```c SNSR_API size_t snsrStreamGetMeta(SnsrStream b, SnsrStreamMeta key); ``` **Parameters and return value:** **Input parameter:** `b` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to query. **Input parameter:** `key` * [StreamMeta](https://doc.sensory.com/tnl/7.8/api/io.md#streammeta) query type. **Return value:** * The value for `key`. **Java** ```java long getMeta(SnsrStreamMeta key); ``` **Parameters and return value:** **Input parameter:** `key` * [StreamMeta](https://doc.sensory.com/tnl/7.8/api/io.md#streammeta) query type. **Return value:** * The value for `key`. Queries stream metadata. Returns [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) metadata, selected by `key`. If an error occurs this function returns `0` and sets the error state in the stream. Use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to check the error state. **Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [StreamMeta](https://doc.sensory.com/tnl/7.8/api/io.md#streammeta) #### open **C/C++** ```c SNSR_API SnsrRC snsrStreamOpen(SnsrStream b); ``` **Parameters and return value:** **Input parameter:** `b` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to open. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java SnsrRC open() throws java.io.IOException; ``` **Parameters and return value:** **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. Opens a stream. Read and write operations are valid only on open streams, and newly created streams are not open. Some stream types can be closed and re-opened. See the [constructors](https://doc.sensory.com/tnl/7.8/api/io.md#constructors) section for details. If re-opening is not supported `open` will return [CANNOT_REOPEN](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) when an attempt is made to open it a second time. #### print **C/C++** ```c SNSR_API size_t snsrStreamPrint(SnsrStream b, const char *format, ...); ``` **Parameters and return value:** **Input parameter:** `b` * Output [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Input parameter:** `format` * [printf()][] style format string. **Input parameter:** `...` * Arguments specified by `format`. **Return value:** * The number of bytes written to `b`, or `0` if an error occurred. **Java** ```java long print(String format, Object... args) throws java.io.IOException; ``` **Parameters and return value:** **Input parameter:** `format` * [printf()][] style format string. **Input parameter:** `args` * Arguments specified by `format`. **Return value:** * The number of bytes written to the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream), or `0` if an error occurred. Prints a formatted string to a stream. This function is similar to [printf()][], but operates on a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instead of a `FILE *`. `print` will open the output stream if it's not already open. If an error occurs this function returns `0` and sets the error state in `b`. Use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to check the error state. **Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC), [printf()][] #### rC **C/C++** ```c SNSR_API SnsrRC snsrStreamRC(SnsrStream b); ``` **Parameters and return value:** **Input parameter:** `b` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Return value:** * The current [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) code for `b`. **Java** ```java SnsrRC rC(); ``` **Parameters and return value:** **Return value:** * The current [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) code for this [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). Retrieves the most recent return code for a stream. **Also see these related items:** [atEnd](https://doc.sensory.com/tnl/7.8/api/io.md#stream-atEnd) #### read **C/C++** ```c SNSR_API size_t snsrStreamRead(SnsrStream a, void *buffer, size_t size, size_t nitems); ``` **Parameters and return value:** **Input parameter:** `a` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to read from. **Output parameter:** `buffer` * Memory to write to. **Input parameter:** `size` * The size of an item, in bytes. **Input parameter:** `nitems` * The number of items to read. **Return value:** * The number of items read. Reads binary data from a stream. Opens the stream if it is not already open, reads `nitems` items, each `size` bytes long, into `buffer` and returns the number of items read. If either `size` or `nitems` is zero this function returns `0` without reading anything. A short read (fewer than `nitems`) will occur only if the end of the stream was reached before `nitems` were read, or if an error occurred. The stream return code will be set appropriately. Use [atEnd](https://doc.sensory.com/tnl/7.8/api/io.md#stream-atEnd) or [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to distinguish between these conditions. If the end of the stream is encountered in the middle of an object, it returns the number of complete items read. The partial object is discarded and the stream remains in the end-of-stream condition. Read operations block until all the requested data have been read, or an error or end-of-stream occurs. **Also see these related items:** [atEnd](https://doc.sensory.com/tnl/7.8/api/io.md#stream-atEnd), [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC), [skip](https://doc.sensory.com/tnl/7.8/api/io.md#stream-skip) **Java** ```java int read() throws java.io.IOException; long read(byte[] buffer) throws java.io.IOException; long read(byte[] buffer, long offset, long count) throws java.io.IOException; ``` **Parameters and return value:** **Return value:** * `int` value of the single byte read, or `Integer.MIN_VALUE` if an error occurred. **Output parameter:** `buffer` * Destination buffer where read data are copied to. **Input parameter:** `offset` * Number of bytes from the beginning of `buffer` where writing will start. **Input parameter:** `count` * Number of bytes to read from the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Return value:** * `long` the number of bytes read. Reads binary data from a stream. These methods open the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) if it's not already open. `#!java int read()` reads a single byte from the stream. `#!java long read(byte[] buffer)` attempts to fill the entire `buffer` with data from the stream and returns the number of bytes read. `#!java long read(byte[] buffer, long offset, long count)` reads up to `count` bytes for the stream into `buffer` starting at `offset` bytes from the start. It returns the number of bytes read. A short read (fewer than `count` bytes) will occur if `buffer` fills up first, the stream ends, or an error occurs. Use [atEnd](https://doc.sensory.com/tnl/7.8/api/io.md#stream-atEnd) or [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to distinguish between these conditions. Read operations block until all the requested data have been read, or an error or end-of-stream occurs. **Also see these related items:** [atEnd](https://doc.sensory.com/tnl/7.8/api/io.md#stream-atEnd), [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC), [skip](https://doc.sensory.com/tnl/7.8/api/io.md#stream-skip) #### release **C/C++** _The C language binding uses reference counting to manage object lifetimes, see [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) and [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) in the [memory management](https://doc.sensory.com/tnl/7.8/api/heap.md#memory-management) section._ **Java** ```java public void release(); ``` Releases the native library handle encapsulated by the [SnsrStream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) class. This method releases native handles immediately. Use this to free up resources without having to depend on garbage collection cycle eventually running. *No instance methods must be invoked after calling this method.* **Example:** ```java SnsrStream s = SnsrStream.fromAudioDevice(); // ... s.release(); s = null; ``` #### skip **C/C++** ```c SNSR_API size_t snsrStreamSkip(SnsrStream a, size_t size, size_t nitems); ``` **Parameters and return value:** **Input parameter:** `a` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to read from. **Input parameter:** `size` * The size of an item, in bytes. **Input parameter:** `nitems` * The number of items to read and discard. **Return value:** * The number of items read and discarded. **Java** ```java long skip(long count) throws java.io.IOException; long skip(long size, long nitems) throws java.io.IOException; ``` **Parameters and return value:** **Input parameter:** `size` * The size of an item, in bytes. `size == 1` if not specified. **Input parameter:** `nitems` * The number of items to read and discard. **Return value:** * The number of items read and discarded. Reads from a stream and discards the results. This function is similar to [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read), but discards the read data instead of writing it to a memory buffer. **Also see these related items:** [atEnd](https://doc.sensory.com/tnl/7.8/api/io.md#stream-atEnd), [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC), [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) #### write **C/C++** ```c SNSR_API size_t snsrStreamWrite(SnsrStream a, const void *buffer, size_t size, size_t nitems); ``` **Parameters and return value:** **Input parameter:** `a` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to write to. **Output parameter:** `buffer` * Memory to read from. **Input parameter:** `size` * The size of an item, in bytes. **Input parameter:** `nitems` * The number of items to write. **Return value:** * The number of items written. Writes from a buffer to a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). Opens the stream if it is not already open, then writes `nitems` from `buffer`, each `size` bytes long, to the stream. Returns the number of items written. Returns less than `nitems` only if an error occurred. Use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to obtain the error code. Write operations block until the requested data have been transferred to the underlying implementation, but may return well before the data have reached their final destination (written to disk, played from a speaker, etc.) **Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC), [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) **Java** ```java long write(int oneByte) throws java.io.IOException; long write(byte[] buffer) throws java.io.IOException; long write(byte[] buffer, long offset, long count) throws java.io.IOException; ``` **Parameters and return value:** **Input parameter:** `oneByte` * A single source byte to write. **Input parameter:** `buffer` * Source buffer data are read from. **Input parameter:** `offset` * Number of bytes from the beginning of `buffer` where reading will start. **Input parameter:** `count` * Number of bytes to write to the [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). **Return value:** * The number of bytes written. Writes data to a stream. `#!java long write(int oneByte)` writes a single byte to this [SnsrStream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) and returns `1`, or `0` in case of an error. `#!java long write(byte[] buffer)` writes `buffer.length` bytes from `buffer` to the stream and returns the number of bytes written. `#!java long write(byte[] buffer, long offset, long count)` writes `count` bytes from `buffer` starting at `offset` bytes from the beginning to the stream. It returns the number of bytes written. These methods open the stream if it's not already open. The number of bytes written will be fewer than the requested amount only if an error occurs. Use [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC) to identify such errors. Write operations block until the requested data have been transferred to the underlying implementation, but may return well before the data have reached their final destination (written to disk, played from a speaker, etc.) **Also see these related items:** [rC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-rC), [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) ### User-defined This section describes the [provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) data structure used with [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) to create custom [stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) types. Each stream must implement at least a subset of the [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open), [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-close), [release](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-release), [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-read), and [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-write) methods. **C/C++** The `data` argument to [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) should point to a `struct` that holds the entire context needed for each instance of a custom stream. Retrieve this pointer in the implementation functions with a call to [getData](https://doc.sensory.com/tnl/7.8/api/io.md#stream-getData). Use [setRC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setRC) and [setDetail](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setDetail) to report any errors encountered. **Java** The `custom` argument to [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) is an object that implements the [SnsrStream.Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) interface. This object should hold the entire context needed for each instance of a custom stream. #### Provider **C/C++** ```c typedef struct { const char *name; // Stream identifier SnsrRC (*open)(SnsrStream b); // (1)! SnsrRC (*close)(SnsrStream b); // (2)! void (*release)(SnsrStream b); // (3)! size_t (*read)(SnsrStream b, void *data, size_t sizeInBytes); // (4)! size_t (*write)(SnsrStream b, const void *data, size_t sizeInBytes); // (5)! } SnsrStream_Vmt; ``` 1. _(optional)_ **Also see these related items:** [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open) Opens the stream 2. _(optional)_ **Also see these related items:** [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-close) Closes the stream 3. _(optional)_ **Also see these related items:** [release](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-release) Releases stream data 4. _(optional)_ **Also see these related items:** [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-read) Reads from the encapsulated data source 5. _(optional)_ **Also see these related items:** [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-write) Writes to the encapsulated data sink [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) virtual method table. This method table defines stream behavior when used as an argument to [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider). This struct must remain valid for the entire life of all the streams of this type. We recommend static allocation. When one of these functions return ([open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open), [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-close)) or [set](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setRC) ([read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-read), [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-write)) an [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok), and additional error detail is available, it should also set a detailed human-readable error message using [setDetail](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setDetail). Set the fields for optional members without implementations to `NULL`. **Also see these related items:** [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) **Java** ```java public interface Provider { public static final long OK = 0; // (6)! public static final long EOF = -1; // (7)! public static final long INTERRUPTED = -2; // (8)! public static final long INVALID_ARG = -3; // (9)! public static final long NOT_IMPLEMENTED = -4; // (10)! public static final long ERROR = -5; // (11)! public static final long NOT_OPEN = -6; // (12)! public long onOpen() throws IOException; // (1)! public long onClose() throws IOException; // (2)! public void onRelease(); // (3)! public long onRead(byte[] buffer) throws IOException; // (4)! public long onWrite(byte[] buffer) throws IOException; // (5)! } ``` 1. **Also see these related items:** [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open) Opens the stream 2. **Also see these related items:** [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-close) Closes the stream 3. **Also see these related items:** [release](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-release) Releases stream data 4. **Also see these related items:** [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-read) Reads from the encapsulated data source 5. **Also see these related items:** [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-write) Writes to the encapsulated data sink 6. Operation successful 7. End-of-stream reached 8. The read or write operation was interrupted 9. Argument validation failed 10. This operation is not implemented, e.g. write operation on a read-only stream 11. All errors that are not `EOF`, `INTERRUPTED`, `INVALID_ARG`, `NOT_IMPLEMENTED`, or `NOT_OPEN` 12. Attempt was made to use a stream that is not open Custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) interface specification. Use this interface to add new stream types. Each [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) type exposes a single [constructor](https://doc.sensory.com/tnl/7.8/api/io.md#constructors) used to create a new instances of this type. The constructor function sets up the required data structures and copies arguments into these structures for use by the [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open) method. The constructor must not open the underlying data stream. The [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open) method will do this instead. Delaying the open operation allows for function compositions, such as a stream that is a concatenation of other streams. Use [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) to create an instance from an object that implements this `SnsrStream.Provider` interface. **Also see these related items:** [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) ##### open **C/C++** ```c SnsrRC (*open)(SnsrStream b); ``` **Parameters and return value:** **Input parameter:** `b` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Opens the underlying data stream. Called in response to an [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open) API call, and only on [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handles that are not already open. Must open the underlying stream in binary mode, unless documented otherwise. Must return [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) if the operation succeeded, and an error code if the resource could not be opened. **Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) **Java** ```java public long onOpen() throws IOException; ``` **Parameters and return value:** **Return value:** * `Provider.OK` on success, `Provider.NOT_OPEN` on failure. Opens the underlying data stream. Called in response to an [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open) API call, and only on [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handles that are not already open. Must open the underlying stream in binary mode, unless documented otherwise. Must return `Provider.OK` if the operation succeeded, or `Provider.NOT_OPEN` if the resource could not be opened. **Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) ##### close **C/C++** ```c SnsrRC (*close)(SnsrStream b); ``` **Parameters and return value:** **Input parameter:** `b` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Closes the underlying data stream. Called in response to a [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-close) API call, and only on [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handles that are currently open. This function must flush buffered output and discard any remaining buffered input. Must return [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) if the operation succeeded, and an error code if the underlying resource could not be closed. **Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) **Java** ```java long onClose() throws IOException; ``` **Parameters and return value:** **Return value:** * `Provider.OK` on success or `Provider` error code on failure. Closes the underlying data stream. Called in response to a [close](https://doc.sensory.com/tnl/7.8/api/io.md#stream-close) API call, and only on [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handles that are currently open. This function must flush buffered output and discard any remaining buffered input. Must return `Provider.OK` if the operation succeeded, and an error code if the underlying resource could not be closed. **Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) ##### release **C/C++** ```c void (*release)(SnsrStream b); ``` **Parameters and return value:** **Input parameter:** `b` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Java** ```java void onRelease(); ``` Releases private [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) data. Called just before the stream handle is de-allocated. The stream will have been [closed](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-close) when this function is called. Must release all the resources allocated by the [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-vmt-open) function. **Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) ##### read **C/C++** ```c size_t (*read)(SnsrStream b, void *data, size_t sizeInBytes); ``` **Parameters and return value:** **Output parameter:** `data` * Memory location to write to. **Input parameter:** `sizeInBytes` * Number of bytes to read from the encapsulated data source. **Input parameter:** `b` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. Reads data from the encapsulated source. Called in response to a [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) API call. The handle will be open when this function is called, and `sizeInBytes` will be larger than `0`. Must read `sizeInBytes` bytes into the buffer pointed to by `data`. The read must block (i.e. not return) until all the requested data have been read, or an error occurs. Must return the number of actual bytes read. This number of bytes read must be `sizeInBytes`, unless: * An error occurred, in which case it must call [setRC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setRC) with an appropriate error code. * The end of the stream was reached, in which case it must call [setRC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setRC) with [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof). **Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) **Java** ```java long onRead(byte[] buffer) throws IOException; ``` **Parameters and return value:** **Output parameter:** `buffer` * Destination buffer. **Return value:** * Number of bytes read from the stream. Reads data from the encapsulated source. Called in response to a [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) API call. The handle will be open when this function is called. Must read `buffer.length` bytes into buffer. The read must block (i.e. not return) until all the requested data have been read, or an error occurs. Must return the number of actual bytes read, unless an error occurred. Returning fewer than `buffer.length` bytes indicates that the end of the stream was reached. Must return `Provider.INTERRUPTED` if the read was interrupted. **Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) ##### write **C/C++** ```c size_t (*write)(SnsrStream b, const void *data, size_t sizeInBytes); ``` **Parameters and return value:** **Input parameter:** `data` * Memory location to read from. **Input parameter:** `sizeInBytes` * Number of bytes to write to the encapsulated data source. **Input parameter:** `b` * [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Return value:** * The number of bytes written. Writes data to the encapsulated data stream. Called in response to a [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) API call. The stream handle will be open when this function is called, and `sizeInBytes` will be larger than `0`. Must write `sizeInBytes` bytes, reading them from the buffer pointed to by `data`. The write must block (i.e. not return) until all of the requested data have been written to the encapsulated sink, or an error occurs. Must return the number of bytes actually written. This number of bytes must be `sizeInBytes`, unless an error occurred, in which case it must call [setRC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setRC) with an appropriate error code. **Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) **Java** ```java long onWrite(byte[] buffer) throws IOException; ``` **Parameters and return value:** **Input parameter:** `buffer` * Source buffer to read from. **Return value:** * The number of bytes written to the stream. Writes data to the encapsulated data stream. Called in response to a [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) API call. The stream handle will be open when this function is called. Must read `buffer.length` bytes from `buffer` and write them to the encapsulated [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). The write must block (i.e. not return) until all of the requested data have been written to the encapsulated sink, or an error occurs. Must return the number of bytes actually written. Return `Provider.INTERRUPTED` if the write operation was interrupted. **Also see these related items:** [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) #### getData **C/C++** ```c SNSR_API void * snsrStream_getData(SnsrStream b); ``` **Parameters and return value:** **Input parameter:** `b` * A custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Return value:** * A pointer to user data. Gets the user data pointer from a custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). Returns the `data` argument passed to the [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) call that created stream `b`. **Also see these related items:** [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider), [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) **Java** Use the `custom` object that implements the [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) interface instead. #### getVmt **C/C++** ```c SNSR_API SnsrStream_Vmt * snsrStream_getVmt(SnsrStream b); ``` **Parameters and return value:** **Input parameter:** `b` * A custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Return value:** * A pointer to the [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) `struct` for `b`. Gets the [virtual method table](https://doc.sensory.com/tnl/7.8/api/io.md#provider) from a custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). Returns the `def` argument passed to the [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) call that created stream `b`. **Also see these related items:** [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider), [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) **Java** Use the `custom` object that implements the [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) interface instead. #### setDetail **C/C++** ```c SNSR_API void snsrStream_setDetail(SnsrStream b, const char *format, ...); ``` **Parameters and return value:** **Input parameter:** `b` * A custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Input parameter:** `format` * [printf()][] style format string. **Input parameter:** `...` * Arguments specified by `format`. Sets a detailed [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) error message. Sets the detailed human-readable error message in stream `b` to `format`, which is a standard C library [printf()][] format string. This detailed error message is made available through the [errorDetail](https://doc.sensory.com/tnl/7.8/api/io.md#stream-errorDetail) API function. **Also see these related items:** [errorDetail](https://doc.sensory.com/tnl/7.8/api/io.md#stream-errorDetail), [setRC](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setRC), [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) **Java** Use `#!java throw new IOException(message);` instead. #### setRC **C/C++** ```c SNSR_API void snsrStream_setDetail(SnsrStream b, const char *format, ...); ``` **Parameters and return value:** **Input parameter:** `b` * A custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle. **Input parameter:** `code` * [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) return code, [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success. This sets the return code for custom [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) `b` to `code`. **Note:** Only a subset of the [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) codes are valid for streams: `code` must be in the range from [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) to [FORMAT_NOT_SUPPORTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). **Also see these related items:** [setDetail](https://doc.sensory.com/tnl/7.8/api/io.md#stream-setDetail), [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider) **Java** Return one of the `SnsrStream.Provider` error codes (e.g. `#!java return Provider.NOT_OPEN;`) instead. ## Enumerations [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) functions and methods use the enumerations below to select from a small set of alternate behaviors. ### StreamAudioFormat **C/C++** ```c typedef enum { SNSR_ST_AF_{name}, ... } SnsrStreamAudioFormat; // Where {name} is from the table below, e.g.: SNSR_ST_AF_DEFAULT ``` **Java** ```java public enum SnsrStreamAudioFormat { {name}, ... } // Where {name} is from the table below, e.g.: SnsrStreamAudioFormat.DEFAULT ``` Audio format specifier for [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream). The default format is 16-bit little-endian LPCM sampled at 16 kHz. Most Sensory models expect this format, making the [DEFAULT](https://doc.sensory.com/tnl/7.8/api/io.md#st_af_default) and [DEFAULT_LOW_LATENCY](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) the most salient. **Also see these related items:** [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice), [fromAudioStream](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiostream) **`DEFAULT`** _(recommended)_ Default audio stream format. **`DEFAULT_LOW_LATENCY`** Low latency, at the expense of higher CPU overhead. **`LPCM_S16_16K`** 16-bit little-endian LPCM at 16 kHz (default). **`LPCM_S16_16K_SAMPLES`** WAV file sample count. **snsrStreamFromAudioDevice() parameters** ```c SNSR_API SnsrStream snsrStreamFromAudioDevice( SNSR_ST_AF_LPCM_S16_16K_SAMPLES, size_t *samples ); ``` - **Output parameter:** `samples`: Number of audio samples read from the RIFF header. **`LPCM_S16_16K_LOW_LATENCY`** Low latency, at the expense of higher CPU overhead. **Also see these related items:** [DEFAULT_LOW_LATENCY](https://doc.sensory.com/tnl/7.8/api/io.md#streamaudioformat) **`DEVICE`** Default format with a user-specified device. **snsrStreamFromAudioDevice() parameters** ```c SNSR_API SnsrStream snsrStreamFromAudioDevice( SNSR_ST_AF_DEVICE, const char *device ); ``` - **Input parameter:** `device`: Platform-specific device selector. **`DEVICE_LOW_LATENCY`** Low-latency default format with a user-specified device. **snsrStreamFromAudioDevice() parameters** ```c SNSR_API SnsrStream snsrStreamFromAudioDevice( SNSR_ST_AF_DEVICE_LOW_LATENCY, const char *device ); ``` - **Input parameter:** `device`: Platform-specific device selector. **`DEVICE_RATE_MODE`** 16-bit LE LPCM with user-specified device, sample rate, and mode. **snsrStreamFromAudioDevice() parameters** ```c SNSR_API SnsrStream snsrStreamFromAudioDevice( SNSR_ST_AF_DEVICE_RATE_MODE, const char *device, unsigned rate, SnsrStreamMode mode ); ``` - **Input parameter:** `device`: Platform-specific device selector. - **Input parameter:** `rate`: Sample rate in Hz. - **Input parameter:** `mode`: Read or write. **Also see these related items:** [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode) **`DEVICE_RATE_MODE_LOW_LATENCY`** Low-latency 16-bit LE LPCM with user-specified device, sample rate, and mode. **snsrStreamFromAudioDevice() parameters** ```c SNSR_API SnsrStream snsrStreamFromAudioDevice( SNSR_ST_AF_DEVICE_RATE_MODE_LOW_LATENCY, const char *device, unsigned it rate, SnsrStreamMode mode ); ``` - **Input parameter:** `device`: Platform-specific device selector. - **Input parameter:** `rate`: Sample rate in Hz. - **Input parameter:** `mode`: Read or write. **Also see these related items:** [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode) **`DEVID`** Default audio format with a user-specified device. **snsrStreamFromAudioDevice() parameters** ```c SNSR_API SnsrStream snsrStreamFromAudioDevice( SNSR_ST_AF_DEVID, int devid ); ``` - **Input parameter:** `devid`: Platform-specific device selector. On Windows, `devid` is the device ID used with the Multimedia Extensions, such as [waveInGetDevCaps()](https://msdn.microsoft.com/en-us/library/dd743841(v=vs.85).aspx). **`DEVID_LOW_LATENCY`** Low-latency default audio format with a user-specified device. **snsrStreamFromAudioDevice() parameters** ```c SNSR_API SnsrStream snsrStreamFromAudioDevice( SNSR_ST_AF_DEVID, int devid ); ``` - **Input parameter:** `devid`: Platform-specific device selector. On Windows, `devid` is the device ID used with the Multimedia Extensions, such as [waveInGetDevCaps()](https://msdn.microsoft.com/en-us/library/dd743841(v=vs.85).aspx). **`DEVID_RATE_MODE`** 16-bit LE LPCM with user-specified device, sample rate, and mode. **snsrStreamFromAudioDevice() parameters** ```c SNSR_API SnsrStream snsrStreamFromAudioDevice( SNSR_ST_AF_DEVID, int devid, unsigned int rate, SnsrStreamMode mode ); ``` - **Input parameter:** `devid`: Platform-specific device selector. - **Input parameter:** `rate`: Sample rate in Hz. - **Input parameter:** `mode`: Read or write. On Windows, `devid` is the device ID used with the Multimedia Extensions, such as [waveInGetDevCaps()](https://msdn.microsoft.com/en-us/library/dd743841(v=vs.85).aspx). **Also see these related items:** [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode) **`DEVID_RATE_MODE_LOW_LATENCY`** Low-latency 16-bit LE LPCM with user-specified device, sample rate, and mode. **snsrStreamFromAudioDevice() parameters** ```c SNSR_API SnsrStream snsrStreamFromAudioDevice( SNSR_ST_AF_DEVID, int devid, unsigned int rate, SnsrStreamMode mode ); ``` - **Input parameter:** `devid`: Platform-specific device selector. - **Input parameter:** `rate`: Sample rate in Hz. - **Input parameter:** `mode`: Read or write. On Windows, `devid` is the device ID used with the Multimedia Extensions, such as [waveInGetDevCaps()](https://msdn.microsoft.com/en-us/library/dd743841(v=vs.85).aspx). **Also see these related items:** [StreamMode](https://doc.sensory.com/tnl/7.8/api/io.md#streammode) ### StreamMeta **C/C++** ```c typedef enum { SNSR_ST_META_{name}, ... } SnsrStreamMeta; // Where {name} is from the table below, e.g.: SNSR_ST_META_BYTES_READ ``` **Java** ```java public enum SnsrStreamMeta { {name}, ... } // Where {name} is from the table below, e.g.: SnsrStreamMeta.BYTES_READ ``` [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) metadata introspection key. **Also see these related items:** [getMeta](https://doc.sensory.com/tnl/7.8/api/io.md#stream-getMeta) **`BYTES_READ`** Number of bytes read from the stream. **`BYTES_WRITTEN`** Number of bytes written to the stream. **`IS_OPEN`** Boolean, `1` if the stream is open, `0` if not. **`IS_READABLE`** Boolean, `1` if the stream is readable, `0` if not. **`IS_WRITABLE`** Boolean, `1` if the stream is writable, `0` if not. **`OPEN_COUNT`** Number of times the stream has been opened. ### StreamMode **C/C++** ```c typedef enum { SNSR_ST_MODE_{name}, ... } SnsrStreamMode; // Where {name} is from the table below, e.g.: SNSR_ST_MODE_READ ``` **Java** ```java public enum SnsrStreamMode { {name}, ... } // Where {name} is from the table below, e.g.: SnsrStreamMode.READ ``` [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) input or output mode. **`READ`** Read from this input stream. **`WRITE`** Write to this output stream. **C/C++** ```c ``` **Parameters and return value:** **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java ``` **Parameters and return value:** **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. --> [AAssetManager]: https://developer.android.com/ndk/reference/group___asset.html "Android Asset access" [ALSA]: http://www.alsa-project.org/main/index.php/ALSA_Library_API "Advanced Linux Sound Architecture" [Audio Queue Services]: https://developer.apple.com/documentation/audiotoolbox/audio-queue-services "Audio Toolbox, Core Audio" [AudioRecord]: https://developer.android.com/reference/android/media/AudioRecord "Android AudioRecord class" [fopen()]: https://en.cppreference.com/w/c/io/fopen "fopen() standard C library function" [getdelim]: https://www.man7.org/linux/man-pages/man3/getdelim.3p.html "Linux manual page for getdelim()" [Java Audio]: https://docs.oracle.com/javase/tutorial/sound/capturing.html "Audio capturing in Java" [MediaRecorder.AudioSource]: https://developer.android.com/reference/android/media/MediaRecorder.AudioSource "Android MediaRecorder.AudioSource" [printf()]: https://en.cppreference.com/w/c/io/fprintf "printf() standard C library function" [Sensory]: https://sensory.com/ "Sensory, Inc. AI on the Edge & Beyond" [Windows Multimedia Extensions]: https://learn.microsoft.com/en-us/windows/win32/api/mmeapi/nf-mmeapi-waveinopen "waveInOpen" *[ALSA]: Advanced Linux Sound Architecture *[API]: Application Programming Interface *[FIFO]: First in, first out *[LPCM]: Linear pulse-code modulation *[RAM]: Random Access Memory *[ROM]: Read-Only Memory, typically nonvolatile flash memory *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/library-config.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/library-config/" --- # Library configuration This section describes functions and settings that control overall TrulyNatural SDK library behavior. These are most useful on small platforms with limited memory, and relevant to the native C API only. Library configuration is not available in other language bindings. Most-used library configuration (C API only): | API | Summary | |-----|---------| | [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) | Set global behavior: heap, clock, license, panic handler, and more. | | [CONFIG_ALLOC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc) | Install a custom [heap allocator](https://doc.sensory.com/tnl/7.8/api/library-config.md#heap-allocators) before any other library call. | | [allocTLSF](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloctlsf) | TLSF allocator backed by a fixed memory pool (recommended). | | [allocStdlib](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocstdlib) | Allocator that wraps the platform `malloc` / `free`. | | [allocLock](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloclock) | Thread-safe wrapper around another allocator VMT. | | [CONFIG_ALLOC_ADD_POOL](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc_add_pool) | Add a memory segment to an existing custom allocator. | | [CONFIG_LICENSE](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_license) | Apply an SDK license key at startup. | | [CONFIG_CLOCK_FUNC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_clock_func) | Register a monotonic real-time [clock](https://doc.sensory.com/tnl/7.8/api/library-config.md#clock) for bare-metal targets. | | [CONFIG_PANIC_FUNC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_panic_func) | Register a fatal [panic](https://doc.sensory.com/tnl/7.8/api/library-config.md#panic) handler for out-of-memory failures. | | [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt) | Vtable for implementing a fully custom heap allocator. | To release library-wide configuration allocations, call [tearDown](https://doc.sensory.com/tnl/7.8/api/heap.md#teardown) (see [Memory management](https://doc.sensory.com/tnl/7.8/api/heap.md#memory-management)). ## Configuration Use the [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) function to replace the [heap memory allocator](https://doc.sensory.com/tnl/7.8/api/library-config.md#heap-allocators), specify a [real-time clock](https://doc.sensory.com/tnl/7.8/api/library-config.md#clock) function, or register an [out-of-memory handler](https://doc.sensory.com/tnl/7.8/api/library-config.md#panic). ### config **C/C++** ```c SNSR_API SnsrRC snsrConfig(SnsrConfig config, ...); ``` **Parameters and return value:** **Input parameter:** `config` * [Config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config-enum) configuration type. This determines the rest of the argument list. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. Global library configuration changes. Use this variadic function to change the overall behavior of the TrulyNatural SDK. The required [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config-enum) parameter specifies which aspect to change. **Warning:** - Unless noted otherwise in the description of the `config` setting, you must call this function only when no library handles exist: Before any other API function at start-up, or after a call to [tearDown](https://doc.sensory.com/tnl/7.8/api/heap.md#teardown). - This function is **not** thread-safe. - The number of additional parameters expected depend entirely on the `config` parameter. Failure to provide all the expected arguments with the expected types will lead to [undefined behavior][undefined-behavior]. **Also see these related items:** [Config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config-enum) ### chipComms **C/C++** ```c typedef uint32_t *(*SnsrChipComms)(uint32_t *in); ``` Security and licensing chip function. **Warning:** Do not use this or [CONFIG_SECURITY_CHIP](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_security_chip) unless recommended by Sensory. **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [CONFIG_SECURITY_CHIP](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_security_chip) ### clock **C/C++** ```c typedef uint64_t (*SnsrClock)(void); ``` Custom clock function. This should return the number of real-time monotonically-increasing clock ticks since an arbitrary start time. **Note:** You'll typically only need to provide this clock function on small platforms that run on bare metal or very lightweight operating systems. The TrulyNatural SDK provides clock implementations on Linux, macOS, iOS, Android, and Windows. **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [CONFIG_CLOCK_FUNC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_clock_func) ### panic **C/C++** ```c typedef void (*SnsrPanic)(const char *format, va_list a); ``` **Parameters and return value:** **Input parameter:** `format` * [printf()][] format string. **Input parameter:** `a` * List of arguments that match the format specifiers in `format`. Fatal error function. When set with [CONFIG_PANIC_FUNC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_panic_func), a function matching this signature will be called if the TrulyNatural SDK fails to allocate memory. **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [CONFIG_PANIC_FUNC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_panic_func) ### Config **C/C++** ```c typedef enum { SNSR_CONFIG_{name}, ... } SnsrConfig; // Where {name} is from the table below, e.g.: SNSR_CONFIG_ALLOC ``` Values in this `enum` are used as the first argument to [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) and specify which additional arguments `snsrConfig()` expects. **`ALLOC`** Replace the heap allocator used in the TrulyNatural SDK. This replaces the standard C heap allocator with a custom library-specific [allocator](https://doc.sensory.com/tnl/7.8/api/library-config.md#heap-allocators). This function will fail if any previous TrulyNatural heap allocations have been made. Best practice is to configure the heap manager before calling any other library functions. **snsrConfig() parameters** ```c SNSR_API SnsrRC snsrConfig( SNSR_CONFIG_ALLOC, SnsrAlloc_Vmt *vmt ); ``` - **Input parameter:** `vmt`: Pointer to [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt). This struct must remain valid at least until [tearDown](https://doc.sensory.com/tnl/7.8/api/heap.md#teardown) is called. **Example** ```c #define SIZE_IN_BYTES 512000 static size_t segment[SIZE_IN_BYTES / sizeof(size_t)]; // in main() snsrConfig(SNSR_CONFIG_ALLOC, snsrAllocTLSF(segment, sizeof(segment))); ``` **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt), [CONFIG_ALLOC_ADD_POOL](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc_add_pool) **`ALLOC_ADD_POOL`** Add a memory pool to a custom heap allocator. This adds an additional memory segment to use as backing store for the custom heap allocator configured with [CONFIG_ALLOC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc). **snsrConfig() parameters** ```c SNSR_API SnsrRC snsrConfig( SNSR_CONFIG_ALLOC_ADD_POOL, void *poolStart, size_t poolSizeInBytes ); ``` - **Input parameter:** `poolStart`: Pointer to start of a read-write memory segment to add to the allocator store. This must be aligned to the words size of the CPU. **Example** Example: ```c #define POOL_SIZE 128000 static size_t pool[POOL_SIZE / sizeof(size_t)]; snsrConfig(SNSR_CONFIG_ALLOC_ADD_POOL, pool, sizeof(pool)); ``` **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [CONFIG_ALLOC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc) **`PANIC_FUNC`** Set the fatal error function. This panic function is called in the event of an unrecoverable error, such as the inability to allocate sufficient RAM.

The default behavior if `panicFunc` is `NULL` is to print an error message to `stderr` and then abort the process. This is undesirable on small embedded platforms with either no OS, or a very lightweight RTOS, that run from a single memory image.

If `panicFunc` is called, all TrulyNatural SDK handles are invalid and must be discarded. An effective way to do this is to use a custom [heap allocator](https://doc.sensory.com/tnl/7.8/api/library-config.md#heap-allocators), which allows all open handles to be abandoned by reclaiming the heap segment. **snsrConfig() parameters** ```c SNSR_API SnsrRC snsrConfig( SNSR_CONFIG_PANIC_FUNC, SnsrPanic panic ); ``` - **Input parameter:** `panic`: [panic](https://doc.sensory.com/tnl/7.8/api/library-config.md#panic) callback function. **Example** Example: ```c #include #include #include static jmp_buf PanicJmp; static void panicFunc(const char *format, va_list a) { fprintf(stderr, "\nPANIC: "); vfprintf(stderr, format, a); fprintf(stderr, "\n\n"); longjmp(PanicJmp, SNSR_RC_NO_MEMORY); } // In main() before any API calls that are not snsrConfig() int r; snsrConfig(SNSR_CONFIG_PANIC_FUNC, panicFunc); if ((r = setjmp(PanicJmp))) { snsrTearDown(); // handle out-of-memory case. Abandon heap, re-initialize. } ``` **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [heap allocators](https://doc.sensory.com/tnl/7.8/api/library-config.md#heap-allocators) **`STT_SUPPORT`** Library Speech-To-Text support. [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) returns [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) if the SDK supports Speech-To-Text models, or [NOT_SUPPORTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_not_supported) if STT support is not available. You may retrieve this value even if active library handles exist. **Note** You must call [new](https://doc.sensory.com/tnl/7.8/api/inference.md#new) at least once before calling `snsrConfig(SNSR_CONFIG_STT_SUPPORT)`. If you do not, this function will return [NOT_SUPPORTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_not_supported) even if the SDK does include support for Speech-To-Text. **snsrConfig() parameters** ```c SNSR_API SnsrRC snsrConfig( SNSR_CONFIG_STT_SUPPORT ); ``` **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [stt-support](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#stt-support) **`THREAD_SUPPORT`** Library multithreading support. [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) returns [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) if the SDK supports running multi-threaded models, or [NOT_SUPPORTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_not_supported) if thread support is not available. You may retrieve this value even if active library handles exist. **snsrConfig() parameters** ```c SNSR_API SnsrRC snsrConfig( SNSR_CONFIG_THREAD_SUPPORT ); ``` **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [thread-support](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#thread-support) **`SECURITY_CHIP`** Hardware security device communication. Use iff recommended by Sensory. **snsrConfig() parameters** ```c SNSR_API SnsrRC snsrConfig( SNSR_CONFIG_SECURITY_CHIP, SnsrChipComms commsFunc ); ``` - **Input parameter:** `commsFunc`: [chipComms](https://doc.sensory.com/tnl/7.8/api/library-config.md#chipcomms) callback function. **Example** Example: ```c uint32_t *chipComms(uint32_t *in) { // communicate with hardware } // ... snsrConfig(SNSR_CONFIG_SECURITY_CHIP, chipComms); ``` **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) **`CLOCK_FUNC`** Set high-resolution monotonic time function and resolution. Sets a function that must return a high-resolution monotonically-increasing value that measures clock time. This is used to limit the maximum amount of time spent in any one call to [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) with [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit), and for recognition pipeline profiling. **snsrConfig() parameters** ```c SNSR_API SnsrRC snsrConfig( SNSR_CONFIG_CLOCK_FUNC, SnsrClock clockFunc, double resolution ); ``` - **Input parameter:** `clockFunc`: [clock](https://doc.sensory.com/tnl/7.8/api/library-config.md#clock) function, returns number of clock ticks. - **Input parameter:** `resolution`: The number of ticks per second. **Example** Example: ```c #include #include static uint64_t clockFunc(void) { struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); return (uint64_t)t.tv_sec * 1e9 + (uint64_t)t.tv_nsec; } int main(int argc, char *argv[]) { snsrConfig(SNSR_CONFIG_CLOCK_FUNC, clockFunc, 1e9); // ... } ``` **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [profile](https://doc.sensory.com/tnl/7.8/api/inference.md#profile), [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) **`LICENSE`** _(since [7.7.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.7.0))_ Apply a software license key. This overrides the software license key embedded in the TrulyNatural SDK library. Use this to extend the expiration date or to enable additional features. [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) returns [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) if the SDK supports overriding license keys and the license key format is valid, [LICENSE_OVERRIDE_NOT_SUPPORTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_license_override_not_supported) if the SDK port does not support override keys, and [LICENSE_OVERRIDE_NOT_ENABLED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_license_override_not_enabled) if the existing library license key does not enable the override feature. **snsrConfig() parameters** ```c SNSR_API SnsrRC snsrConfig( SNSR_CONFIG_LICENSE, const char *key, const char *secret ); ``` - **Input parameter:** `key`: This a cryptographically signed license key provided by Sensory. Use `NULL` to disable an existing key. - **Input parameter:** `secret`: Secret string required to validate the key signature. Can be `NULL`. Provided by Sensory. **Example** This key expired on 2026-01-01 and disables all features. Do not use it your own code. ```c const char *key = "eyJ2ZXIiOjEsInBsZCI6ImV5SnNhV05sYm5ObFpTSTZJbE5" "sYm5OdmNua2dRMjl1Wm1sa1pXNTBhV0ZzSUNBZ0lDSXNJbT" "F2WkhWc1pYTWlPaUl3SWl3aVpYaHdJam9pTmprMU5qSTVPR" "EFpTENKamJHbGxiblJKWkNJNklqQWlMQ0ppZFdsc1pDSTZP" "VFo5Iiwic2lnIjoiNjJLa0I2K2Nvdi9Fd2Y2eGppdDNlSWg" "xZDVrR1BCYmo3N3BLUWVqU3ZQSkg1Z0RqVGd6VWtOSCtBak" "diMTcwS2VUNThNN1laQmkwcG1lTEtGNWswRFE9PSJ9"; const char *secret = "019bb450-caa7-7c2a-b796-960f7d61dc2a"; snsrConfig(SNSR_CONFIG_LICENSE, key, secret); ``` **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [license keys](https://doc.sensory.com/tnl/7.8/reference/overview.md#license-keys) **`LICENSE_INFO`** _(since [7.8.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.8.0))_ Inspect an override license key field. Returns the string value for the specified override software license key field.**Private function** Do not use this without explicit instructions from Sensory.

[config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) returns [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) if the SDK supports overriding license keys and the license key format is valid, [LICENSE_OVERRIDE_NOT_VALID](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) if the override key does not exist or did not pass validation, [LICENSE_OVERRIDE_NOT_SUPPORTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_license_override_not_supported) if the SDK port does not support override keys, and [LICENSE_OVERRIDE_NOT_ENABLED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_license_override_not_enabled) if the existing library license key does not enable the override feature. The returned string value is reference-counted. You must call [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) on it before it goes out of scope or a memory leak will result. The returned value will be `NULL` if the named field does not exist in the license key.

**snsrConfig() parameters** ```c SNSR_API SnsrRC snsrConfig( SNSR_CONFIG_LICENSE, const char *field, const char *value ); ``` - **Input parameter:** `field`: The name of an override license key field. - **Output parameter:** `value`: The string value for `field`. Reference-counted. Must be [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release)d. **Example** ```c const char *expires; SnsrRC r = snsrConfig(SNSR_CONFIG_LICENSE_INFO, "exp", &expires); ``` **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [LICENSE](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_license), [license keys](https://doc.sensory.com/tnl/7.8/reference/overview.md#license-keys) **`LICENSE_SUPPORT`**

_(since [7.8.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.8.0))_ Software license key override support. [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) returns [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) if the SDK supports overriding license keys, [LICENSE_OVERRIDE_NOT_SUPPORTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_license_override_not_supported) if the SDK port does not include support for overriding keys, and [LICENSE_OVERRIDE_NOT_ENABLED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_license_override_not_enabled) if the existing library license key does not enable the override feature.

You may retrieve this value even if active library handles exist. **snsrConfig() parameters** ```c SNSR_API SnsrRC snsrConfig( SNSR_CONFIG_LICENSE_SUPPORT ); ``` **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [LICENSE](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_license), [library-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-info) ## Heap allocators You can replace the heap memory allocator (`malloc()`, `realloc()`, `free()`) used by the TrulyNatural SDK with alternate implementations. This is most useful on small platforms where a standard library implementation is either not available, or not recommended, or RAM use must be strictly constrained. By default this library uses the dynamic memory allocation functions defined in `stdlib.h`. We provide allocator implementations [allocBuddy](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocbuddy), [allocStdlib](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocstdlib), [allocTLSF](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloctlsf) (recommended), and an API for [creating your own](https://doc.sensory.com/tnl/7.8/api/library-config.md#user-defined-allocator). ### allocBuddy **C/C++** ```c SNSR_API const SnsrAlloc_Vmt * snsrAllocBuddy(void *poolStart, size_t poolSizeInBytes); ``` **Parameters and return value:** **Input parameter:** `poolStart` * Points to the start of a read-write memory segment to use as the allocator backing store. This address **must** be aligned to the word size of the CPU. **Input parameter:** `poolSizeInBytes` * the number of bytes available at `poolStart`. **Return value:** * A new custom allocator definition. Buddy allocator. This is an implementation of the [Buddy memory allocation][bmem] heap allocation algorithm. The size of returned blocks is the smallest power-of-two in which the requested block size fits. This allocator is fast and has low external fragmentation, but this comes at the expense of significant internal fragmentation (e.g. a 1025 byte request requires allocation of a 2048 byte block, wasting 1023 bytes). This is a customization of the [memsys5 allocator from SQLite][mem5] that is in the Public Domain. **Example:** ```c #define POOL_SIZE 128000 static size_t pool[POOL_SIZE / sizeof(size_t)]; // in main, before any other snsr* calls snsrConfig(SNSR_CONFIG_ALLOC, snsrAllocBuddy(pool, sizeof(pool))); ``` **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [CONFIG_ALLOC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc) ### allocLock **C/C++** ```c SNSR_API const SnsrAlloc_Vmt * snsrAllocLock(const SnsrAlloc_Vmt *vmt); ``` **Parameters and return value:** **Input parameter:** `vmt` * A custom allocator definition. **Return value:** * A new custom allocator definition that is thread-safe. Thread-safe allocator wrapper. This takes a [heap allocator](https://doc.sensory.com/tnl/7.8/api/library-config.md#heap-allocators) and adds mutual exclusion locks to make it thread-safe. This wrapper has no effect if the TrulyNatural SDK does not have thread support on the target platform: The function adds the lock wrapper only if `snsrConfig(SNSR_CONFIG_THREAD_SUPPORT) == SNSR_RC_OK`. **Example:** ```c #define POOL_SIZE 128000 static size_t pool[POOL_SIZE / sizeof(size_t)]; // in main, before any other snsr* calls snsrConfig(SNSR_CONFIG_ALLOC, snsrAllocLock(snsrAllocTLSF(pool, sizeof(pool)))); ``` **Also see these related items:** [allocBuddy](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocbuddy), [allocStdlib](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocstdlib), [allocTLSF](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloctlsf) ### allocPerf **C/C++** ```c SNSR_API const SnsrAlloc_Vmt * snsrAllocPerf(const SnsrAlloc_Vmt *vmt); ``` **Parameters and return value:** **Input parameter:** `vmt` * A custom allocator definition. **Return value:** * A new custom allocator definition that gathers allocation statistics. Statistics-gathering allocator wrapper. Adds instrumentation to an allocator to determine the heap high-water mark, number of allocations, internal fragmentation overhead, etc. **Warning:** This wrapper adds mutual exclusion locks to the wrapped allocator. Do not use with [allocLock](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloclock), as that will result in deadlock or undefined behavior. **Note:** type: example ```c // in main, before any other snsr* calls snsrConfig(SNSR_CONFIG_ALLOC, snsrAllocPerf(snsrAllocStdlib())); // application code snsrTearDown(); snsrAllocPerfStats(snsrStreamFromFILE(stdout, SNSR_ST_MODE_WRITE)); ``` **Also see these related items:** [allocBuddy](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocbuddy), [allocStdlib](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocstdlib), [allocTLSF](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloctlsf), [allocPerfStats](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocperfstats) ### allocPerfStats **C/C++** ```c SNSR_API size_t snsrAllocPerfStats(SnsrStream out); ``` **Parameters and return value:** **Input parameter:** `out` * A writable [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) to receive allocator statistics, or `NULL` to produce no output. **Return value:** * The smallest heap pool size required to repeat the instrumented allocation run. Show allocator statistics Returns the smallest heap pool size that could be sufficient to repeat the instrumented allocation run. To reduce the chance of out-of-heap errors, allocate a pool that is at least 10% larger than this minimum. If the `out` [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) not `NULL`, this function writes heap allocator statistics in human-readable form to this stream. **Note:** Requires use of [allocPerf](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocperf) to gather statistics. **Also see these related items:** [allocPerf](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocperf) ### allocStdlib **C/C++** ```c SNSR_API const SnsrAlloc_Vmt * snsrAllocStdlib(void); ``` **Parameters and return value:** **Return value:** * A new custom allocator definition. Standard C library allocator. This is the standard library allocator: `malloc()`, `realloc()`, and `free()`. It is the default heap allocator used unless overridden with [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config). **Warning:** This allocator is not thread-safe. If your application runs TrulyNatural SDK code from more than one execution thread you must add mutual exclusion locking by wrapping this allocator with [allocLock](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloclock). Whether this allocator works with [allocPerf](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocperf) depends on whether the standard C library for the platform has a `malloc_usable_size()` or `malloc_size()` implementation available. If in doubt, use [allocTLSF](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloctlsf) for performance measurement instead. **Example:** ```c // in main, before any other snsr* calls snsrConfig(SNSR_CONFIG_ALLOC, snsrAllocStdlib()); ``` **Also see these related items:** [allocLock](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloclock), [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [CONFIG_ALLOC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc) ### allocTLSF - recommended **C/C++** ```c SNSR_API const SnsrAlloc_Vmt * snsrAllocTLSF(void *poolStart, size_t poolSizeInBytes); ``` **Parameters and return value:** **Input parameter:** `poolStart` * Points to the start of a read-write memory segment to use as the allocator backing store. This address **must** be aligned to the word size of the CPU. **Input parameter:** `poolSizeInBytes` * the number of bytes available at `poolStart`. **Return value:** * A new custom allocator definition. TLSF allocator. We recommend this [Two-level Segregated Fit][tlsf] allocator for embedded systems. It has `O(1)` cost for most operations, low overhead, low internal fragmentation, and supports multiple backing store pools for the heap. This a customization of a [TLSF library][tlsfv3] that is in the Public Domain. **Warning:** This allocator is not thread-safe. If your application runs TrulyNatural SDK code from more than one execution thread you must add mutual exclusion locking by wrapping this allocator with [allocLock](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloclock). **Example:** ```c #define POOL_SIZE 128000 static size_t pool[POOL_SIZE / sizeof(size_t)]; // in main, before any other snsr* calls snsrConfig(SNSR_CONFIG_ALLOC, snsrAllocTLSF(pool, sizeof(pool))); ``` **Also see these related items:** [allocLock](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloclock), [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [CONFIG_ALLOC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc) ## User-defined allocator You can create your own custom [heap allocator](https://doc.sensory.com/tnl/7.8/api/library-config.md#heap-allocators) by implementing the functions defined in [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt), and then calling [`snsrConfig(SNSR_CONFIG_ALLOC, &vmt)`](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc). ### alloc_Vmt **C/C++** ```c typedef struct { void *(*malloc)(void *ctx, size_t size); // (1)! void (*free)(void *ctx, void *ptr); // (2)! void *(*realloc)(void *ctx, void *ptr, size_t size); // (3)! size_t (*size)(void *ctx, void *ptr); // (4)! size_t (*roundUp)(void *ctx, size_t size); // (5)! size_t (*minPoolSize)(void *ctx, size_t maxAlloc, size_t maxCount); // (6)! SnsrAllocRC (*addPool)(void *ctx, void *pool, size_t size); // (7)! SnsrAllocRC (*setUp)(void *ctx); // (8)! SnsrAllocRC (*tearDown)(void *ctx); // (9)! void *ctx; // Allocator context (10) } SnsrAlloc_Vmt; ``` 1. _(required)_ **Also see these related items:** [malloc](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-malloc) 2. _(required)_ **Also see these related items:** [free](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-free) 3. _(required)_ **Also see these related items:** [realloc](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-realloc) 4. _(optional)_ **Also see these related items:** [size](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-size) 5. _(optional)_ **Also see these related items:** [roundUp](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-roundUp) 6. _(optional)_ **Also see these related items:** [minPoolSize](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-minPoolSize) 7. _(optional)_ **Also see these related items:** [addPool](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-addPool) 8. _(optional)_ **Also see these related items:** [setUp](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-setUp) 9. _(optional)_ **Also see these related items:** [tearDown](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-tearDown) 10. _(required)_ `ctx` should point to the custom allocator data structure. It is passed to each implementation method as the first argument. User-defined allocator virtual method table. This method table defines a heap allocator to use in place of `malloc()`, `realloc()`, and `free()` from `stdlib.h`. The struct must remain valid until a call to [tearDown](https://doc.sensory.com/tnl/7.8/api/heap.md#teardown), or the application ends. **Example:** This minimal example wraps the standard C library allocator. ```c static void * vmtMalloc(void *ctx, size_t size) { return malloc(size); } static void * vmtRealloc(void *ctx, void *ptr, size_t size) { return realloc(ptr, size); } static void vmtFree(void *ctx, void *ptr) { free(ptr); } static const SnsrAlloc_Vmt CustomAlloc = { vmtMalloc, vmtFree, vmtRealloc, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; // In main, before any other snsr* calls snsrConfig(SNSR_CONFIG_ALLOC, &CustomAlloc); ``` **Also see these related items:** [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config), [CONFIG_ALLOC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc), [AllocRC](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocrc), [malloc](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-malloc), [free](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-free), [realloc](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-realloc), [size](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-size), [roundUp](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-roundUp), [minPoolSize](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-minPoolSize), [addPool](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-addPool), [setUp](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-setUp), [tearDown](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-tearDown) #### malloc - required **C/C++** ```c void *(*malloc)(void *ctx, size_t size); ``` **Parameters and return value:** **Input parameter:** `ctx` * The value of the `ctx` member in [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt). **Input parameter:** `size` * Number of bytes to allocate. `size > 0`. **Return value:** * A pointer to an aligned segment of writable memory, or `NULL` if memory could not be allocated. Allocate memory from the heap. This method should work like the standard library's `malloc()` function. It should return a pointer to at least `size` bytes of writable memory, aligned to at least the word size of the CPU. **Also see these related items:** [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt) #### free - required **C/C++** ```c void (*free)(void *ctx, void *ptr); ``` **Parameters and return value:** **Input parameter:** `ctx` * The value of the `ctx` member in [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt). **Input parameter:** `ptr` * Pointer to previously allocated heap segment, as returned by [malloc](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-malloc), or [realloc](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-realloc). Free memory allocated with the malloc or realloc methods. This method should work like the standard library's `free()` function. **Also see these related items:** [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt) #### realloc - required **C/C++** ```c void *(*realloc)(void *ctx, void *ptr, size_t size); ``` **Parameters and return value:** **Input parameter:** `ctx` * The value of the `ctx` member in [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt). **Input parameter:** `ptr` * Pointer to previously allocated heap segment, as returned by [malloc](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-malloc), or [realloc](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-realloc). **Input parameter:** `size` * Number of bytes to allocate. **Return value:** * A pointer to an aligned segment of writable memory, or `NULL` if memory could not be allocated. Allocate memory from the heap. This method should work like the standard library's `malloc()` function. It should return a pointer to at least `size` bytes of writable memory, aligned to at least the word size of the CPU. **Also see these related items:** [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt) #### size - optional **C/C++** ```c size_t (*size)(void *ctx, void *ptr); ``` **Parameters and return value:** **Input parameter:** `ctx` * The value of the `ctx` member in [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt). **Input parameter:** `ptr` * Pointer to previously allocated heap segment, as returned by [malloc](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-malloc), or [realloc](https://doc.sensory.com/tnl/7.8/api/library-config.md#vmt-realloc). **Return value:** * The size of the memory block `ptr` points to. Return the size of the ptr allocation. This method should work like `malloc_size()` or `malloc_usable_size()`. It should return the actual size of the block of memory allocated for `ptr`. This will typically be a bit larger than the requested size. **Note:** This method is optional and used only by [allocPerf](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocperf). If the allocation size is not available, set this method to `NULL` and avoid using [allocPerf](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocperf). **Also see these related items:** [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt) #### roundUp - optional **C/C++** ```c size_t (*roundUp)(void *ctx, size_t size); ``` **Parameters and return value:** **Input parameter:** `ctx` * The value of the `ctx` member in [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt). **Input parameter:** `size` * Request size in bytes. **Return value:** * The size of the block that would be allocated for request `size`. Return the allocation size for a given request size. This returns the size of the block that would be allocated when requesting a `size` byte segment. **Note:** This method is optional. If set to `NULL`, the block size will be the requested `size` rounded up to the next multiple of 8. **Also see these related items:** [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt) #### minPoolSize - optional **C/C++** ```c size_t (*minPoolSize)(void *ctx, size_t maxAlloc, size_t maxCount); ``` **Parameters and return value:** **Input parameter:** `ctx` * The value of the `ctx` member in [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt). **Input parameter:** `maxAlloc` * The high water mark of bytes allocated by the instrumented application. **Input parameter:** `maxCount` * The high water mark of the number of allocations made by the application. **Return value:** * An estimate of the smallest backing store pool that could satisfy `maxAlloc` and `maxCount`. Return an estimate of the pool size required. This method returns an estimate of the smallest allocator pool required to repeat an instrumented run. **Note:** This method is optional. If set to `NULL`, the estimated pool size will not be available in [allocPerfStats](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocperfstats) **Also see these related items:** [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt) #### addPool - optional **C/C++** ```c SnsrAllocRC (*addPool)(void *ctx, void *pool, size_t size); ``` **Parameters and return value:** **Input parameter:** `ctx` * The value of the `ctx` member in [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt). **Input parameter:** `pool` * `void *` to the start of a read-write memory segment to use as additional allocator store. This address must be aligned to the word size of the CPU. **Input parameter:** `size` * The number of bytes available at `pool`. **Return value:** * [ALLOC_RC_OK](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_rc_ok) upon success, any other [AllocRC](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocrc) on failure. Add a new backing store pool to the allocator. This method adds a new pool to the backing store used for the heap. **Note:** This method is optional. If set to `NULL`, the allocator does not support adding pools to the heap store. **Also see these related items:** [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt), [AllocRC](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocrc) #### setUp - optional **C/C++** ```c SnsrAllocRC (*setUp)(void *ctx); ``` **Parameters and return value:** **Input parameter:** `ctx` * The value of the `ctx` member in [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt). **Return value:** * [ALLOC_RC_OK](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_rc_ok) upon success, any other [AllocRC](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocrc) on failure. Initialize the memory allocator. This method is called before any other to initialize the allocator. **Note:** This method is optional. If set to `NULL`, no additional initialization is done. **Also see these related items:** [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt), [AllocRC](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocrc) #### tearDown - optional **C/C++** ```c SnsrAllocRC (*tearDown)(void *ctx); ``` **Parameters and return value:** **Input parameter:** `ctx` * The value of the `ctx` member in [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt). **Return value:** * [ALLOC_RC_OK](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_rc_ok) upon success, any other [AllocRC](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocrc) on failure. Shut down the memory allocator. This method should deallocate any resources this allocator initialized. **Note:** This method is optional. If set to `NULL`, no additional deallocation is done. **Also see these related items:** [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt), [AllocRC](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocrc) ### AllocRC **C/C++** ```c typedef enum { SNSR_ALLOC_RC_{name}, ... } SnsrAllocRC; // Where {name} is from the table below, e.g.: SNSR_ALLOC_RC_OK ``` This is the return code used by the implementation methods in [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt). **Also see these related items:** [alloc_Vmt](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloc_vmt) **`OK`** Success. **`ERROR`** Unspecified failure. **`ALLOCATOR_EXISTS`** Allocator already configured. **`ALLOC_FAILED`** Out of heap memory. **`NO_FUNC`** Required implementation method is `NULL`. **`NOT_SUPPORTED`** Not supported by this allocator. **C/C++** ```c ``` **Parameters and return value:** **Input parameter:** `s` * [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. **Return value:** * [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) for success, any other value indicates failure. **Java** ```java ``` **Parameters and return value:** **Return value:** * The same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance, for method chaining. --> [bmem]: https://en.wikipedia.org/wiki/Buddy_memory_allocation "Buddy memory allocation" [mem5]: https://www.sqlite.org/malloc.html#memsys5 "Zero-malloc memory allocator" [printf()]: https://en.cppreference.com/w/c/io/fprintf "printf() standard C library function" [tlsf]: http://www.gii.upv.es/tlsf/main/docs "Two-level Segregated Fit allocator" [tlsfv3]: https://github.com/OlegHahm/tlsf/tree/27c65c2966dfc6f7055fbeaf63141ce39cc1f16c "TLSF library v3" [undefined-behavior]: https://en.wikipedia.org/wiki/Undefined_behavior "Undefined program behavior" *[API]: Application Programming Interface *[iff]: if, and only if *[RAM]: Random Access Memory *[RTOS]: Real-Time Operating System *[SDK]: Software Development Kit *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/overview.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/overview/" --- # API overview This is a brief overview of the [API design goals](https://doc.sensory.com/tnl/7.8/api/overview.md#design-goals), the SDK's [conceptual model](https://doc.sensory.com/tnl/7.8/api/overview.md#conceptual-model), and the two supported [audio processing modes](https://doc.sensory.com/tnl/7.8/api/overview.md#processing-modes). ## Design goals The TrulyNatural SDK API is a result of these design goals: * Pure C implementation. * Lowest common denominator, widest toolchain availability. * No C++ runtime overhead. * Fast. * Simple API. * Small footprint: limited number of functions and data types. * Generic, independent of the inference task. * Fundamental data types only: floating point, integer, strings, streams, and opaque object instance handles. * Make it easier to provide bindings for languages other than C. * Flexible configuration. * Hide complexity, * but still allow for fine-grained configuration if needed. * Settings indexed by string names, documented settings define public API. * One self-contained model per task. * Model includes a flow graph that specifies how various low-level internal modules (feature extractors, acoustic models, etc.) connect and interact. * Includes all required module configurations. * Run on a wide variety of platforms, including ones without file system support. There is a significant downside to these design choices: Discoverability is very limited. You cannot determine model behavior from function or method names alone. You must refer to the [model type](https://doc.sensory.com/tnl/7.8/models/types/index.md#model-types) documentation for expected task behavior and [available settings](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys). ## Conceptual model This library uses a [dataflow][] approach to evaluate speech recognition tasks. It uses [inversion of control][]: The SDK invokes [event](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) handlers to report [results](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#results) and control task flow. The API contains two primary data types: [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) used for model [inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference), and a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) abstraction for [input and output](https://doc.sensory.com/tnl/7.8/api/io.md#input-and-output). Sessions hold the entire state of a model instance, and use streams for all input and output. There is, for example, a single [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) function to load a model into a session, but this supports loading from a [named file](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename), an open [FILE *](https://doc.sensory.com/tnl/7.8/api/io.md#fromfile) handle, a [memory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory) segment, from the [code](https://doc.sensory.com/tnl/7.8/api/io.md#fromcode) segment, and from compressed [assets](https://doc.sensory.com/tnl/7.8/api/io.md#fromasset) on Android. Models (`snsr` files) define flow pipelines and session behavior. These contain the serialized content[^1] of the session flow graph, including all binary models and configurations. Think of these as hierarchical key-value databases. Once loaded into a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session), you can query or change the [setting keys](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) with generic [getter](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) and [setter](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) functions. [^1]: Similar in concept to [protocol buffers][], but with streamed unpacking into native data structures in RAM, no need for accessor functions, and additional features such as conversion to [code](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source) for running from the text segment. ## Processing modes We support two modes for audio processing: * **Pull** mode, where the [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) function reads audio from the configured input stream. This blocks on read until new data are available. The [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) function returns only when the stream runs out of data (for example the end of a file), an [event](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) handler tells it to stop, or an error occurs. * **Push** mode, where the application repeatedly calls the [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) function with small chunks of the audio data. The [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) function returns once it has processed or buffered these data. The application eventually calls [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop) to flush and process any buffered data. Model evaluation typically follows this recipe: **Pull mode** 1. Create a new session instance with [new](https://doc.sensory.com/tnl/7.8/api/inference.md#new). 2. [Load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) a task model into the instance. 3. [Set](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) the [input](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm) source stream. 4. [Register](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) one or more [event](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) handlers. 5. Enter the main loop by calling [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run). The library will process the input streams and invoke event handlers at appropriate times. The main loop continues until a terminating condition is reached, such as an event returning an error code. 6. [Release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) the session instance. **Also see these related items:** [Your first program](https://doc.sensory.com/tnl/7.8/getting-started/your-first-program.md#your-first-program), [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spotc), [evalUDT.java](https://doc.sensory.com/tnl/7.8/api/sample/java/evalUDT.md#evaludtjava) **Push mode** 1. Create a new session instance with [new](https://doc.sensory.com/tnl/7.8/api/inference.md#new). 2. [Load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) a task model into the instance. 3. [Register](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) one or more [event](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) handlers. 4. Process audio segments by calling [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) repeatedly. This will invoke event handlers before `push` returns. 5. Call [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop) once to flush any buffered audio. 6. [Release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) the session instance. **Also see these related items:** [push-audio.c](https://doc.sensory.com/tnl/7.8/api/sample/c/push-audio.md#push-audioc) ## Language bindings This version of the TrulyNatural SDK supports two language bindings: [C][] and [Java][]. There's a one-to-one mapping between C functions and Java methods, with these idiomatic differences to translate between them. **Naming.** A C function `snsrXxx(SnsrSession s, ...)` becomes a Java method `Session.xxx(...)` — the `Snsr` prefix and the `SnsrSession` first argument are absorbed into the receiver. For example, `snsrSetHandler(s, key, c)` ↔ `s.setHandler(key, c)`. **Return values and error handling.** The C binding uses a *latched-error* model: every function returns [SnsrRC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), and once a session enters an error state, every subsequent call short-circuits with the same code until [clearRC](https://doc.sensory.com/tnl/7.8/api/inference.md#clearrc) (or [reset](https://doc.sensory.com/tnl/7.8/api/inference.md#reset)) is called. Read the latched code with [rC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) and the human-readable detail with [errorDetail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail). The Java binding does not surface latched errors to callers. Each Java method either completes successfully or throws an exception describing the failure; subsequent method calls on the same session start fresh. Six methods that perform I/O — [Session.load](https://doc.sensory.com/tnl/7.8/api/inference.md#load), [Session.run](https://doc.sensory.com/tnl/7.8/api/inference.md#run), and [Stream.copy](https://doc.sensory.com/tnl/7.8/api/io.md#stream-copy), [Stream.getDelim](https://doc.sensory.com/tnl/7.8/api/io.md#stream-getDelim), [Stream.open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open), [Stream.read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read), [Stream.skip](https://doc.sensory.com/tnl/7.8/api/io.md#stream-skip), [Stream.write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) — declare `throws java.io.IOException` and so are checked. All other exceptions are unchecked subclasses of `java.lang.RuntimeException`. The mapping from [SnsrRC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) to Java exception class is part of the binding's contract: | Java exception class | Thrown for [SnsrRC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) codes such as | Typical cause | | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `java.io.IOException` (checked) | [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof), [STREAM](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end), [NOT_OPEN](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [BUFFER_OVERRUN](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [BUFFER_UNDERRUN](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [DELIM_NOT_FOUND](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [LIBRARY_TOO_OLD](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) | Stream I/O failed or reached end-of-data. Only thrown from the six methods that declare `throws IOException`; identical conditions outside those methods raise `RuntimeException`. | | `java.lang.OutOfMemoryError` | [NO_MEMORY](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [NOT_ENOUGH_SPACE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) | Allocation failed. | | `java.lang.IllegalArgumentException` | [INVALID_ARG](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [INVALID_HANDLE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [INCORRECT_SETTING_TYPE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_incorrect_setting_type), [SETTING_IS_READ_ONLY](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [FORMAT_NOT_SUPPORTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [VERSION_MISMATCH](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) | The caller passed a value that is the wrong type, the wrong format, or otherwise unacceptable. | | `java.lang.IndexOutOfBoundsException` | [SETTING_NOT_FOUND](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [SETTING_NOT_AVAILABLE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [VALUE_NOT_SET](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [ARG_OUT_OF_RANGE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [NAME_NOT_UNIQUE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [ITERATION_LIMIT](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) | A lookup by name, index, or port missed; or a numeric / iteration limit was exceeded. | | `java.lang.RuntimeException` | All other non-OK codes — `ERROR`, `NOT_IMPLEMENTED`, `CONFIGURATION_*`, `ELEMENT_*`, `LICENSE_*`, `NO_MODEL`, `NOT_INITIALIZED`, `NOT_SUPPORTED`, `TIMED_OUT`, and so on. | Misconfiguration, license issue, internal API violation, or the catch-all bucket. | Callbacks that need to control the run loop without raising an exception may return any of [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok), [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end), [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop), [SKIP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_skip), [REPEAT](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_repeat), or [TIMED_OUT](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_timed_out); any other return value from a callback is translated into an exception by the same mapping. Java methods that have no out-parameters in C return the [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance instead, so callers chain freely: ```java s.load(input).setHandler(KEY, listener).run(); ``` When an exception is thrown, the underlying [SnsrRC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) code remains available on the [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) (or [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream)) for the duration of the `catch` block: call [rC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) to read it programmatically, or [errorDetail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail) for the human-readable message. (The exception's `getMessage()` is set to the same `errorDetail` text.) This is useful when the exception class alone is too coarse — for example, distinguishing a missing setting from an unsupported one when both surface as `IndexOutOfBoundsException`: ```java try { s.set(KEY, value).run(); } catch (IndexOutOfBoundsException e) { if (s.rC() == SnsrRC.SETTING_NOT_FOUND) { // Treat as a config-file typo, fall back to a default. } else { throw e; } } ``` The handler does not need to do anything to "reset" the session — as above, the next method call on the same session starts fresh. **Memory management.** The C binding uses [reference counting](https://doc.sensory.com/tnl/7.8/api/heap.md#memory-management) on every [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session), [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream), and [Callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback) handle (and on the C string returned by [getString](https://doc.sensory.com/tnl/7.8/api/inference.md#getters)); manage lifetimes with [retain](https://doc.sensory.com/tnl/7.8/api/heap.md#retain) and [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release). The Java binding uses standard garbage collection. Explicit `retain` / `release` are not exposed in Java and are not needed; [Session.release()](https://doc.sensory.com/tnl/7.8/api/inference.md#session-release) is provided for callers who want to free native resources promptly without waiting for GC, but is otherwise optional. [C]: https://en.wikipedia.org/wiki/C_(programming_language) "C programming language" [dataflow]: https://en.wikipedia.org/wiki/Flow-based_programming "Flow-based programming" [inversion of control]: https://en.wikipedia.org/wiki/Inversion_of_control [Java]: https://en.wikipedia.org/wiki/Java_(programming_language) "Java programming language" [protocol buffers]: https://en.wikipedia.org/wiki/Protocol_Buffers *[API]: Application Programming Interface *[RAM]: Random Access Memory *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/android/SnsrStreamAudioDeviceAndroid.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/android/SnsrStreamAudioDeviceAndroid/" --- # SnsrStreamAudioDeviceAndroid.java This is the source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) implementation for Android. It provides a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) adapter for [Android Audio][AudioRecord]. **Also see these related items:** [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/android/misc/SnsrStreamAudioDeviceAndroid.java_ **SnsrStreamAudioDeviceAndroid.java:** ```java /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ * * Android AudioRecord to read-only SnsrStream adapter. *------------------------------------------------------------------------------ */ package com.sensory.speech.snsr; import java.io.IOException; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.media.MediaRecorder.AudioSource; import com.sensory.speech.snsr.SnsrStream; /* * Implements the SnsrStream.Provider interface for live audio. * * Create a new SnsrStream instance with: * SnsrStream a = SnsrStream.fromProvider(new SnsrStreamAudioDeviceAndroid(16000), * SnsrStreamMode.READ); */ class SnsrStreamAudioDeviceAndroid implements SnsrStream.Provider { private static final String TAG = "SnsrStreamAudioDeviceAndroid"; private static final int CHANNELS = AudioFormat.CHANNEL_IN_MONO; private static final int ENCODING = AudioFormat.ENCODING_PCM_16BIT; private int mSource = AudioSource.VOICE_RECOGNITION; /* Use an audio buffer that is at least this long */ private static final int MIN_BUFFER_SIZE_MS = 1000; private AudioRecord mAudio; private int mBufferSize; private int mSampleRate; /** * Static constructor. * @param[in] sampleRate the sample rate. Use 16000. */ public SnsrStreamAudioDeviceAndroid(int source, int sampleRate) { double minBufferSize = (double)sampleRate * MIN_BUFFER_SIZE_MS / 1000; mBufferSize = AudioRecord.getMinBufferSize(sampleRate, CHANNELS, ENCODING); if (mBufferSize < minBufferSize) { mBufferSize = mBufferSize * (int)Math.ceil(minBufferSize / mBufferSize); } mSampleRate = sampleRate; mSource = source; } /** * Static constructor with VOICE_RECOGNITION source. * @param[source] recording source. * @param[in] sampleRate the sample rate. Use 16000. */ public SnsrStreamAudioDeviceAndroid(int sampleRate) { this(AudioSource.VOICE_RECOGNITION, sampleRate); } @Override public long onOpen() throws IOException { mAudio = new AudioRecord(mSource, mSampleRate, CHANNELS, ENCODING, mBufferSize); if (mAudio == null || mAudio.getState() != AudioRecord.STATE_INITIALIZED) { mAudio = null; throw new IOException("Could not initialize audio device at " + mSampleRate + " Hz."); } try { mAudio.startRecording(); } catch (IllegalStateException e) { mAudio = null; throw new IOException(e.toString()); } return OK; } @Override public long onClose() throws IOException { try { mAudio.stop(); } catch (IllegalStateException e) { // ignore } mAudio.release(); mAudio = null; return OK; } @Override public void onRelease() { if (mAudio != null) mAudio.release(); mAudio = null; } @Override public long onRead(byte[] buffer) throws IOException { int read = mAudio.read(buffer, 0, buffer.length); if (Thread.interrupted()) return INTERRUPTED; if (read == AudioRecord.ERROR_BAD_VALUE) return INVALID_ARG; else if (read < 0) return ERROR; return read; } @Override public long onWrite(byte[] buffer) throws IOException { return NOT_IMPLEMENTED; } } ``` [AudioRecord]: https://developer.android.com/reference/android/media/AudioRecord "Android AudioRecord class" *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/android/enroll-trigger.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger/" --- # enroll-trigger This example shows how to enroll a user-defined wake word (UDT, trigger, key word spotter). ## Instructions ### Build - Using [Android Studio][as]: - Open _sample/android/enroll-udt/_ as an existing Android Studio project. - Connect your device, or create an emulator instance Please note that the sample records audio at 16 kHz, which is not universally supported in the emulator. - Press the Play button to build and run the app. - Using Gradle on the command line: - Ensure that `java -version` reports version 17 or later. - Open a terminal window and change the working directory to the _sample/android/enroll-udt_ subdirectory of the TrulyNatural SDK installation. - Set the `ANDROID_HOME` environment to point to the Android SDK. For example: ```sh export ANDROID_HOME=$HOME/Library/Android/sdk ``` - Connect your device. - Run `#!sh ./gradlew installDebug` or `#! gradlew.bat installDebug` ### Run 1. Open the `EnrollTrigger` app. 2. Pick an enrollment phrase such as "Hello blue genie." 3. Press "ENROLL" and follow the instructions. - Say the phrase when prompted. - Enrollment will continue until three good recordings have been made. If an enrollment does not pass the quality checks the reason for the failure, along with a suggestion on how to correct it, will be shown. 4. Once enrollment is complete, press "TALK" 5. Say the enrollment phrase. 6. When spotted, the log window will show the beginning and end times of the phrase relative to the start of the audio stream, and the speaker verification, [sv-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sv-score). ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/android/enroll-udt/app/src/main/java/com/sensory/speech/snsr/demo/enrolltrigger/_ ### Enroll.java This class does UDT enrollment. **Enroll.java:** ```java /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ *------------------------------------------------------------------------------ */ package com.sensory.speech.snsr.demo.enrolltrigger; import android.content.Context; import android.media.MediaRecorder.AudioSource; import android.util.Log; import com.sensory.speech.snsr.Snsr; import com.sensory.speech.snsr.SnsrRC; import com.sensory.speech.snsr.SnsrSession; import com.sensory.speech.snsr.SnsrStream; import java.io.File; import java.io.IOException; import java.util.Locale; import java.util.Random; @SuppressWarnings({"SameParameterValue", "SameReturnValue"}) class Enroll implements SnsrSession.Listener { private static final String TAG = "Enroll"; private static final String ENROLL_VERSION = "~0.8.0 || 1.0.0"; private static final String TARGET = null; // Set to (e.g.) "pc38" to produce embedded output. private static final Boolean SAVE_ENROLLMENT_AUDIO = false; private static final double MIN_SAMPLES = (16000 * 0.2); private static final String EnrollSubDir = "/enroll/"; private static final String[] PromptContext = { "it is me.", "will it rain tomorrow?", "what is Google trading at?" }; static File getOutDir(Context context) { return new File(context.getFilesDir(), EnrollSubDir); } private static int mEnroll = 0; private final MainActivity mUi; private final String mModelFile, mOutFile, mTriggerPhrase; private final File enrollDir; private Boolean mShowPrompt = true; private int mContextIndex = 0; private SnsrStream mAudio; // saved for use across event handlers private File getDirectory() { return enrollDir; } private void saveEmbeddedModel(SnsrSession task, String streamKey, String fileName) { SnsrStream out = SnsrStream.fromFileName(fileName, "w"); try { out.copy(task.getStream(streamKey)); } catch (IOException e) { Log.e(TAG, e.toString()); } out.close(); out.release(); Log.i(TAG, "Wrote " + streamKey + " to " + fileName); } private void saveEmbeddedModels(SnsrSession s, String target, String filePrefix) { SnsrSession task = new SnsrSession(); try { task.load(s.getStream(Snsr.MODEL_STREAM)); task.setString(Snsr.EMBEDDED_TARGET, target); saveEmbeddedModel(task, Snsr.EMBEDDED_HEADER_STREAM, getPath(filePrefix + "-sch.h")); saveEmbeddedModel(task, Snsr.EMBEDDED_SEARCH_STREAM, getPath(filePrefix + "-sch.bin")); saveEmbeddedModel(task, Snsr.EMBEDDED_ACMODEL_STREAM, getPath(filePrefix + "-net.bin")); } catch (IOException e) { Log.e(TAG, e.toString()); } task.release(); } private String getPath(String fileName) { return new File(getDirectory(), fileName).getAbsolutePath(); } String getOutPath() { return getPath(mOutFile); } private Thread mRecogThread; public Enroll(MainActivity mainActivity, String triggerPhrase, String modelFile, String outFile) { mUi = mainActivity; mTriggerPhrase = triggerPhrase; mModelFile = modelFile; enrollDir = getOutDir(mainActivity); //noinspection ResultOfMethodCallIgnored enrollDir.mkdirs(); mOutFile = outFile; } public synchronized void start() { if (mRecogThread == null) { Log.d(TAG, "Starting enroll thread."); mRecogThread = new Thread(new Runnable() { @Override public void run() { try { doEnroll(); } catch (Exception e) { e.printStackTrace(); } } }); mRecogThread.start(); } } public synchronized void stop() { if (mRecogThread != null && mRecogThread.isAlive()) { Log.d(TAG, "Stopping enroll thread."); mRecogThread.interrupt(); try { mRecogThread.join(); mRecogThread = null; } catch (InterruptedException e) { /* ignore */ } } } private void doEnroll() { // Use the microphone audio source, which typically features automatic gain control. mAudio = SnsrStream.fromAudioDevice(AudioSource.MIC, SnsrStream.DEFAULT_SAMPLE_RATE); // Could also chain these, like so: // SnsrSession session = new SnsrSession().load(mModelFile).require(..).setStream(..).setString(..).setHandler(..) SnsrSession session = new SnsrSession(); try { mUi.log("Loading " + mModelFile); session.load(mModelFile) .require(Snsr.TASK_TYPE, Snsr.ENROLL) .require(Snsr.TASK_VERSION, ENROLL_VERSION); } catch (IOException e) { Log.e(TAG, e.toString()); } session.setStream(Snsr.SOURCE_AUDIO_PCM, mAudio); // the user defined phrase to be enrolled session.setString(Snsr.USER, mTriggerPhrase); // Add in some handlers for important lifecycle events session.setHandler(Snsr.FAIL_EVENT, this); session.setHandler(Snsr.PASS_EVENT, this); session.setHandler(Snsr.PROG_EVENT, this); session.setHandler(Snsr.PAUSE_EVENT, this); session.setHandler(Snsr.RESUME_EVENT, this); session.setHandler(Snsr.DONE_EVENT, this); // You can also define a handler class anonymously inline session.setHandler(Snsr.SAMPLES_EVENT, new SnsrSession.Listener() { @Override public SnsrRC onEvent(SnsrSession snsrSession, String s) { if (mShowPrompt && snsrSession.getDouble(Snsr.RES_SAMPLES) >= MIN_SAMPLES) { promptForPhrase(snsrSession); mShowPrompt = false; } return SnsrRC.OK; } } ); mShowPrompt = true; try { session.run(); // Optional: save enrollment context // session.save(SnsrDataFormat.RUNTIME, xyz); } catch (IOException e) { Log.e(TAG, e.toString()); } // Optional but good practice. finalize() will (eventually) release. session.release(); mAudio.release(); } public SnsrRC onEvent(SnsrSession s, String key) { Log.i(TAG, "SNSR Event: " + key); switch (key) { case Snsr.FAIL_EVENT: return onFail(s); case Snsr.PASS_EVENT: return onPass(s); case Snsr.PROG_EVENT: return onProgress(s); case Snsr.PAUSE_EVENT: return onPause(s); case Snsr.RESUME_EVENT: return onResume(s); case Snsr.DONE_EVENT: return onDone(s); default: Log.e(TAG, "Failed to implement handler for: "+key); return SnsrRC.OK; } } private SnsrRC onFail(SnsrSession s) { Log.e(TAG, "FAILED: " + s.getString(Snsr.RES_REASON)); Log.e(TAG, " FIX: " + s.getString(Snsr.RES_GUIDANCE)); mUi.log("FAILED: " + s.getString(Snsr.RES_REASON)); mUi.log(" FIX: " + s.getString(Snsr.RES_GUIDANCE)); /* Save failed enrollment recording for debugging * can get it with ADB */ if (SAVE_ENROLLMENT_AUDIO) { SnsrStream audio = s.getStream(Snsr.AUDIO_STREAM); if (audio != null) { final String path = getPath(String.format(Locale.US, "fail-%02d.wav", mEnroll++)); SnsrStream out = SnsrStream.fromAudioFile(path, "w"); try { out.copy(audio); } catch (IOException e) { Log.e(TAG, e.toString()); } out.release(); } } return SnsrRC.OK; } private SnsrRC onPass(SnsrSession s) { mUi.log("Audio is good."); /* Save good enrollment recording for debugging * Can be retrieved via ADB */ if (SAVE_ENROLLMENT_AUDIO) { SnsrStream audio = s.getStream(Snsr.AUDIO_STREAM); if (audio != null) { final String path = getPath(String.format(Locale.US, "pass-%02d.wav", mEnroll++)); SnsrStream out = SnsrStream.fromAudioFile(path, "w"); try { out.copy(audio); } catch (IOException e) { Log.e(TAG, e.toString()); } out.release(); } } return SnsrRC.OK; } private SnsrRC onProgress(SnsrSession s) { if (Thread.interrupted()) return SnsrRC.INTERRUPTED; double p = s.getDouble(Snsr.RES_PERCENT_DONE); String progressNotice = String.format(Locale.US, "Adapting: %3.0f%% done.", p); if (p >= 100) progressNotice = "Adapting complete!"; mUi.log(progressNotice); return SnsrRC.OK; } @SuppressWarnings("UnusedParameters") private SnsrRC onPause(SnsrSession s) { mAudio.close(); mUi.log("Checking enrollment quality."); return SnsrRC.OK; } @SuppressWarnings("UnusedParameters") private SnsrRC onResume(SnsrSession s) { try { if (s.getInt(Snsr.ADD_CONTEXT) == 0) mContextIndex = -1; else mContextIndex = (new Random()).nextInt(PromptContext.length); mShowPrompt = true; mAudio.open(); } catch (IOException e) { Log.e(TAG, "Error resuming audio: " + e); return SnsrRC.STREAM; } Log.d(TAG, "open RC: " + mAudio.rC()); return SnsrRC.OK; } private SnsrRC onDone(SnsrSession s) { final String outPath = getOutPath(); SnsrStream out = SnsrStream.fromFileName(outPath, "w"); try { out.copy(s.getStream(Snsr.MODEL_STREAM)); } catch (IOException e) { Log.e(TAG, e.toString()); } out.close(); //noinspection ConstantConditions if (TARGET != null) saveEmbeddedModels(s, TARGET, "embedded-" + TARGET); mUi.notify(UiState.ENROLLED); return SnsrRC.STOP; } private void promptForPhrase(SnsrSession s) { int targetCount = s.getInt(Snsr.ENROLLMENT_TARGET); int currentCount = s.getInt(Snsr.RES_ENROLLMENT_COUNT) + 1; String prompt = "\nSAY: " + mTriggerPhrase; if (mContextIndex >= 0) prompt += " " + PromptContext[mContextIndex]; prompt += " (" + currentCount + " / " + targetCount + ")"; mUi.log(prompt); } } ``` ### PhraseSpot.java This class runs the enrolled wake word recognizer. **PhraseSpot.java:** ```java /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ *------------------------------------------------------------------------------ */ package com.sensory.speech.snsr.demo.enrolltrigger; import android.util.Log; import com.sensory.speech.snsr.Snsr; import com.sensory.speech.snsr.SnsrRC; import com.sensory.speech.snsr.SnsrSession; import com.sensory.speech.snsr.SnsrStream; import java.io.IOException; import java.util.Locale; @SuppressWarnings({"SameParameterValue", "CanBeFinal", "UnusedReturnValue"}) class PhraseSpot implements SnsrSession.Listener { private final String TAG = "PhraseSpot"; private Thread mRecogThread; private String mModelPath; private double mTimeout = 0.0; private int mSampleRate; private double mSamples; private double mSamplesTimeoutBegin; private MainActivity mUi; PhraseSpot(MainActivity mainActivity, String model, double timeout) { mUi = mainActivity; mModelPath = model; mTimeout = timeout; mSamples = mSamplesTimeoutBegin = 0; } public synchronized void start() { if (mRecogThread == null) { Log.d(TAG, "Starting recognition thread."); mRecogThread = new Thread(new Runnable() { @Override public void run() { doPhraseSpot(); } }); mRecogThread.start(); } } public synchronized void stop() { if (mRecogThread != null && mRecogThread.isAlive()) { Log.d(TAG, "Stopping recognition thread."); mRecogThread.interrupt(); try { mRecogThread.join(); mRecogThread = null; } catch (InterruptedException e) { /* ignore */ } } } private SnsrRC doPhraseSpot() { Log.d(TAG, "Loading from " + mModelPath + "\n"); SnsrStream audio = SnsrStream.fromAudioDevice(); // Could also chain these, like so: // SnsrSession session = new SnsrSession().load(mModelPath).require(..).setStream(..).setHandler(..) SnsrSession session = new SnsrSession(); try { session.load(mModelPath); session.require(Snsr.TASK_TYPE, Snsr.PHRASESPOT); session.setStream(Snsr.SOURCE_AUDIO_PCM, audio); session.setHandler(Snsr.RESULT_EVENT, this); // In case timeout set mSampleRate = session.getInt(Snsr.SAMPLE_RATE); session.setHandler(Snsr.SAMPLES_EVENT, this); session.run(); } catch (IOException e) { /* ignore */ } this.onEvent(session, "stopped"); SnsrRC rc = session.rC(); // Release the underlying C handles immediately, rather than waiting for GC. session.release(); audio.release(); return rc; } @Override public SnsrRC onEvent(SnsrSession s, String key) { if (!Snsr.SAMPLES_EVENT.equals(key)) Log.i(TAG, "SNSR Event: " + key); switch (key) { case Snsr.SAMPLES_EVENT: if (mTimeout == 0) return SnsrRC.OK; mSamples = s.getDouble(Snsr.RES_SAMPLES); double elapsedSamples = mSamples - mSamplesTimeoutBegin; if (elapsedSamples > mTimeout * mSampleRate) { mUi.log("Phrase spot timed out."); return SnsrRC.TIMED_OUT; } else return SnsrRC.OK; case Snsr.RESULT_EVENT: // Start timeout all over again when we hear the trigger mSamplesTimeoutBegin = mSamples; mUi.log(String.format(Locale.US, "\"%s\", score: %.3f", s.getString(Snsr.RES_TEXT), s.getDouble(Snsr.RES_SV_SCORE))); // Try changing this to Snsr.PHONE_LIST s.forEach(Snsr.WORD_LIST, new SnsrSession.Listener() { @Override public SnsrRC onEvent(SnsrSession s, String key) { mUi.log(String.format(Locale.US, " [%4.0f, %4.0f] %s\n", s.getDouble(Snsr.RES_BEGIN_MS), s.getDouble(Snsr.RES_END_MS), s.getString(Snsr.RES_TEXT))); return SnsrRC.OK; } }); return SnsrRC.OK; case "stopped": mUi.notify(UiState.BEFORE_ENROLL); return SnsrRC.OK; default: Log.e(TAG, "Failed to implement handler for: "+key); return SnsrRC.OK; } } } ``` [as]: https://developer.android.com/studio/index.html "Android Studio" *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets --- source_path: "api/sample/android/index.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/android/" --- # Android examples The Android sample programs and code snippets are available in _sample/android/_ in the TrulyNatural installation directory. See _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/android/_ New to the Session API? Start with [Your first program](https://doc.sensory.com/tnl/7.8/getting-started/your-first-program.md#your-first-program) for the Android wake-word flow, then explore the samples below. ## Examples [enroll-trigger](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#enroll-trigger) - UDT enrollment and phrase spotting. [snsr-debug](https://doc.sensory.com/tnl/7.8/api/sample/android/snsr-debug.md#snsr-debug) - Logs recognizer audio and event timing information using the [tpl-spot-debug](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-debug) template. [SnsrStreamAudioDeviceAndroid.java](https://doc.sensory.com/tnl/7.8/api/sample/android/SnsrStreamAudioDeviceAndroid.md#snsrstreamaudiodeviceandroidjava) - Source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) implementation for [Android Audio][AudioRecord]. [AudioRecord]: https://developer.android.com/reference/android/media/AudioRecord "Android AudioRecord class" *[API]: Application Programming Interface *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets --- source_path: "api/sample/android/snsr-debug.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/android/snsr-debug/" --- # snsr-debug This sample shows how to log recognizer audio and event timing debug information using the [tpl-spot-debug](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-debug) template. ## Instructions ### Build - Using [Android Studio][as] - Open _sample/android/snsr-debug/_ as an existing Android Studio project. - Connect your device, or create an emulator instance. Note that the sample records audio at 16 kHz, which is not universally supported in the emulator. - Press the Play button to build and run the app. - Using Gradle on the command line: - Ensure that `java -version` reports version 17 or later. - Open a terminal window and change the working directory to the _sample/android/snsr-debug_ subdirectory of the TrulyNatural SDK installation. - Set the `ANDROID_HOME` environment to point to the Android SDK. For example: ```sh export ANDROID_HOME=$HOME/Library/Android/sdk ``` - Connect your device. - Run `#!sh ./gradlew installDebug` or `#! gradlew.bat installDebug` ### Run 1. Run the app on you device - Open the `SnsrDebug` app. - Select one of the Recognition options: - Wakeword - Wakeword+Commands - _(stt)_ Speech-To-Text - _(stt)_ Wakeword+Speech-To-Text - Check "Enable Debugging". - Press "TALK", follow instructions. - Press "STOP" when you're done. 2. Copy the `snsrlog` files from the device to the host. **macOS and Linux** ```sh adb -d shell "run-as com.sensory.speech.snsr.demo.snsrdebug \ tar -C /data/user/0/com.sensory.speech.snsr.demo.snsrdebug/files -cf - logs" | tar xvf - ``` **Windows** ```sh adb -d shell "run-as com.sensory.speech.snsr.demo.snsrdebug \ tar -C /data/user/0/com.sensory.speech.snsr.demo.snsrdebug/files -cf - logs" > logs.tar ``` You can use [7-zip][] to extract the `tar` archive: ```sh 7za -y -ttar x logs.tar ``` 3. Extract text, audio and the spotter model with [snsr-log-split](https://doc.sensory.com/tnl/7.8/tools/snsr-log-split.md#snsr-log-split). The number embedded in each `snsrlog` filename the time when the data capture started, in seconds since the [epoch][]. ```sh snsr-log-split -v logs/SnsrDebug-*.snsrlog ``` 4. Check audio quality with [audio-check](https://doc.sensory.com/tnl/7.8/tools/audio-check.md#audio-check) on each of the extracted recordings. ```sh # Check the app for the file basename. audio-check -v SnsrDebug-1757808596.wav ``` 5. To delete old data logs from your device: ```sh adb -d shell "run-as com.sensory.speech.snsr.demo.snsrdebug \ rm -rf /data/user/0/com.sensory.speech.snsr.demo.snsrdebug/files" ``` ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/android/snsr-debug/app/src/main/java/com/sensory/speech/snsr/demo/snsrdebug/_ ### PhraseSpot.java This class runs the selected recognizer (wake word, wake word followed by a command set, STT or wake word followed by STT) and optionally captures audio and event timing information. The [audio processing mode](https://doc.sensory.com/tnl/7.8/api/overview.md#processing-modes) defaults to _push_. Change this to _pull mode_ by modifying the `#!java RUNMODE` variable: ```java private final RunMode RUNMODE = RunMode.PULL; // set to PUSH or PULL ``` **PhraseSpot.java:** ```java /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ *------------------------------------------------------------------------------ */ package com.sensory.speech.snsr.demo.snsrdebug; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.util.Log; import com.sensory.speech.snsr.Snsr; import com.sensory.speech.snsr.SnsrDataFormat; import com.sensory.speech.snsr.SnsrRC; import com.sensory.speech.snsr.SnsrSession; import com.sensory.speech.snsr.SnsrStream; import java.io.File; import java.io.IOException; import java.util.Locale; @SuppressWarnings({"SameParameterValue", "CanBeFinal", "UnusedReturnValue"}) class PhraseSpot implements SnsrSession.Listener { private final String TAG = "PhraseSpot"; private final Boolean VERBOSE = false; // set to true for additional event callbacks private final RunMode RUNMODE = RunMode.PUSH; // set to PUSH or PULL private final int BLOCKSIZE = 480; // size in bytes of a 15 mS audio block captured at 16 KHz // add for push mode HandlerThread private static final int MSG_RESET = 1; private static final int MSG_PUSH = 2; private static final int MSG_STOP = 3; private Thread mRecogThread; private Handler mPushHandler; private final RecogMode mRecogMode; private String mLogPath; private final double mTimeout; private int mSampleRate; private double mSamples; private double mSamplesTimeoutBegin; private final MainActivity mUi; private boolean mDebugging; private volatile boolean mRunning = false, mStopping = false; private HandlerThread mPushHandlerThread; PhraseSpot(MainActivity mainActivity, RecogMode recogMode, double timeout) { mUi = mainActivity; mRecogMode = recogMode; mTimeout = timeout; mSamples = mSamplesTimeoutBegin = 0; mLogPath = null; mDebugging = false; } public void enableDebugging(String logPath) { mDebugging = true; mLogPath = logPath; } public synchronized void start() { if (mRecogThread == null) { mRunning = true; Log.d(TAG, "Starting recognition thread."); mRecogThread = new Thread(new Runnable() { @Override public void run() { doPhraseSpot(); } }); mRecogThread.start(); } } public synchronized void stop() { if (mRecogThread != null && mRecogThread.isAlive()) { Log.d(TAG, "Stopping recognition thread."); mRunning = false; try { mRecogThread.join(); mRecogThread = null; } catch (InterruptedException ignored) {} } } private SnsrRC doPhraseSpot() { SnsrStream audio = SnsrStream.fromAudioDevice(); SnsrSession session = new SnsrSession(); String prompt; try { if (mRecogMode == RecogMode.WW_ONLY) { session.load(assetToString(BuildConfig.TRIGGER_MODEL)); prompt = "Say 'Voice Genie'"; } else if (mRecogMode == RecogMode.WW_CMDS) { session.load(assetToString(BuildConfig.SEQUENTIAL_TEMPLATE)); session.setStream(Snsr.SLOT_0, SnsrStream.fromFileName(assetToString(BuildConfig.TRIGGER_MODEL),"r")); session.setStream(Snsr.SLOT_1, SnsrStream.fromFileName(assetToString(BuildConfig.COMMAND_MODEL),"r")); prompt = "Say 'Voice Genie' followed by one of: \n'Play music'\n'Pause music'\n'Stop music'\n'Next song'\n'Previous song'"; } else if (BuildConfig.SDK_TYPE.equals("tnl-stt") && ((mRecogMode == RecogMode.STT_ONLY || mRecogMode == RecogMode.WW_STT))) { session.load(assetToString(BuildConfig.OPT_SPOT_VAD_LVCSR_TEMPLATE)); session.setStream(Snsr.PHRASESPOT, SnsrStream.fromFileName(assetToString(BuildConfig.TRIGGER_MODEL),"r")); session.setStream(Snsr.LVCSR, SnsrStream.fromFileName(assetToString(BuildConfig.STT_MODEL),"r")); session.setInt(Snsr.INCLUDE_LEADING_SILENCE, 1); if (mRecogMode == RecogMode.WW_STT) { session.setString(Snsr.SLOT, Snsr.SLOT_0); prompt = "Say 'Voice Genie' followed by an automotive command (eg 'Turn on the radio' or 'open the rear hatch')"; } else { session.setString(Snsr.SLOT, Snsr.SLOT_1); prompt = "Say an automotive command (eg 'set the AC to 72' or 'roll down the driver's window')"; } } else { throw new Exception("Unknown recognition mode"); } if (mDebugging) { // Create debug session SnsrSession debug = new SnsrSession(); debug.load(assetToString(BuildConfig.DEBUG_TEMPLATE)); debug.setString(Snsr.DEBUG_LOG_FILE, mLogPath); debug.setInt(Snsr.INCLUDE_MODEL, 0); // Load existing session into the debug model SnsrStream modelData = SnsrStream.fromBuffer(1<<20, 1<<30); session.save(SnsrDataFormat.CONFIG, modelData); session.release(); debug.setStream(Snsr.SLOT_0, modelData); modelData.release(); // Replace session with the the same model wrapped in the tpl-spot-debug template session = debug; // Show the debug log file name in the UI File file = new File(mLogPath); mUi.logToConsole("\nAudio will be logged to " + file.getName()); } // Main result handler session.setHandler(Snsr.RESULT_EVENT, this); // Get sample rate in case timeout was set mSampleRate = session.getInt(Snsr.SAMPLE_RATE); session.setHandler(Snsr.SAMPLES_EVENT, this); // These events exist only for a subset of the models, we therefore // ignore any errors while attempting to set them. try { if (mDebugging) { session.setHandler(Snsr.SLOT_0 + Snsr.SLOT_0 + Snsr.RESULT_EVENT, this); } else { session.setHandler(Snsr.SLOT_0 + Snsr.RESULT_EVENT, this); } } catch (Exception ignored) {} try { session.setHandler(Snsr.NLU_INTENT_EVENT, this); } catch (Exception ignored) {} if (VERBOSE) { try { session.setHandler(Snsr.LISTEN_BEGIN_EVENT, this); } catch (Exception ignored) {} try { session.setHandler(Snsr.LISTEN_END_EVENT, this); } catch (Exception ignored) {} try { session.setHandler(Snsr.BEGIN_EVENT, this); } catch (Exception ignored) {} try { session.setHandler(Snsr.END_EVENT, this); } catch (Exception ignored) {} } session.reset(); // clear error codes reported by rC() mUi.logToConsole("\n" + prompt +"\n"); if (RUNMODE == RunMode.PULL) { // pull mode - the session will read audio and process it internally session.setStream(Snsr.SOURCE_AUDIO_PCM, audio); session.run(); } else { // push mode - the application code reads the audio and passes it to the session startHandlerThread(session); do { byte[] buffer; buffer = new byte[BLOCKSIZE]; long bytesRead = audio.read(buffer); // since audio.read blocks execution while it waits for an audio block to // become available, move session.push into its own Handler mPushHandler.sendMessage(Message.obtain(null, MSG_PUSH, buffer)); } while (session.rC() == SnsrRC.OK && audio.rC() == SnsrRC.OK); mPushHandler.sendMessage(Message.obtain(null, MSG_STOP)); try { mPushHandlerThread.join(); mPushHandlerThread = null; } catch (InterruptedException ignored) {} mPushHandler = null; } } catch (IOException e) { Log.e(TAG, "Error loading and starting model", e); mUi.logToConsole("ERROR: " + e.getMessage()); } catch (Exception e) { Log.e(TAG, "Initialization error" + e); mUi.logToConsole("ERROR: " + e.getMessage()); } this.onEvent(session, "stopped"); SnsrRC rc = session.rC(); // Release the underlying native handles immediately, rather than waiting for GC. session.release(); audio.release(); return rc; } // Format a BuildConfig model filename to an "assets/models" string private String assetToString(String assetName) { return new File("assets/models", assetName.replace(':', '-')).toString(); } // in push mode, run the SnsrSession in its own HandlerThread. private void startHandlerThread(SnsrSession session) { mPushHandlerThread = new HandlerThread("pushMode"); mPushHandlerThread.start(); mPushHandler = new Handler(mPushHandlerThread.getLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_PUSH: byte[] data = (byte[]) msg.obj; //Log.d(TAG, "stt.push called with " + data.length + " bytes"); session.push(Snsr.SOURCE_AUDIO_PCM, data); break; case MSG_STOP: session.stop(); mPushHandlerThread.quit(); break; } } }; } @Override public SnsrRC onEvent(SnsrSession s, String key) { if (!Snsr.SAMPLES_EVENT.equals(key)) Log.i(TAG, "SNSR Event: " + key); switch (key) { case Snsr.SAMPLES_EVENT: // used to implement timeout after 30 seconds of no speech if (!mRunning) return SnsrRC.STOP; if (mTimeout == 0) return SnsrRC.OK; mSamples = s.getDouble(Snsr.RES_SAMPLES); double elapsedSamples = mSamples - mSamplesTimeoutBegin; // Log.d(TAG, "elapsedSamples = " + elapsedSamples); if (elapsedSamples > mTimeout * mSampleRate) { if (!mStopping) mUi.logToConsole("Phrase spot timed out.\n"); mStopping = true; return SnsrRC.TIMED_OUT; } else return SnsrRC.OK; case Snsr.SLOT_0 + Snsr.RESULT_EVENT: // callback for a wakeword result in WW_CMDS mode mUi.logToConsole(String.format(Locale.US, "Wakeword: '%s'", s.getString(Snsr.SLOT_0 + Snsr.RES_TEXT))); return SnsrRC.OK; case Snsr.SLOT_0 + Snsr.SLOT_0 + Snsr.RESULT_EVENT: // callback for a wakeword result in WW_STT mode mUi.logToConsole(String.format(Locale.US, "Wakeword: '%s'", s.getString(Snsr.SLOT_0 + Snsr.SLOT_0 + Snsr.RES_TEXT))); return SnsrRC.OK; case Snsr.RESULT_EVENT: // Reset timeout counter after a result mSamplesTimeoutBegin = mSamples; mUi.logToConsole(String.format(Locale.US, "Result: '%s'\n", s.getString(Snsr.RES_TEXT))); if (VERBOSE) { // print individual words in the result // Try changing this to Snsr.PHONE_LIST for phonemes s.forEach(Snsr.WORD_LIST, new SnsrSession.Listener() { @Override public SnsrRC onEvent(SnsrSession s, String key) { mUi.logToConsole(String.format(Locale.US, " [%4.0f, %4.0f] %s", s.getDouble(Snsr.RES_BEGIN_MS), s.getDouble(Snsr.RES_END_MS), s.getString(Snsr.RES_TEXT))); return SnsrRC.OK; } }); } return SnsrRC.OK; case Snsr.LISTEN_BEGIN_EVENT: case Snsr.LISTEN_END_EVENT: case Snsr.BEGIN_EVENT: case Snsr.END_EVENT: // misc sequential and VAD events (VAD requires TrulyNatural SDK) mUi.logToConsole(String.format(Locale.US, "Event: '%s'", key)); return SnsrRC.OK; case Snsr.NLU_INTENT_EVENT: // NLU intents for STT_ONLY and WW_STT recogModes (Requires TrulyNatural SDK) mUi.logToConsole(String.format(Locale.US, "Intent: '%s' = '%s'", s.getString(Snsr.RES_NLU_INTENT_NAME), s.getString(Snsr.RES_NLU_INTENT_VALUE))); s.forEach(Snsr.NLU_ENTITY_LIST, new SnsrSession.Listener() { @Override public SnsrRC onEvent(SnsrSession s, String key) { mUi.logToConsole(String.format(Locale.US, "Entity: '%s' = '%s'", s.getString(Snsr.RES_NLU_ENTITY_NAME), s.getString(Snsr.RES_NLU_ENTITY_VALUE))); return SnsrRC.OK; } }); return SnsrRC.OK; case "stopped": // custom event callback to reset screen buttons and checkboxes mUi.notify(UiState.NOT_TALKING); return SnsrRC.OK; default: Log.e(TAG, "Failed to implement handler for: " + key); return SnsrRC.OK; } } } ``` [7-zip]: http://www.7-zip.org/ [as]: https://developer.android.com/studio/index.html "Android Studio" [epoch]: https://en.wikipedia.org/wiki/Unix_time "Unix time" *[API]: Application Programming Interface *[SDK]: Software Development Kit *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/c/alsa-stream.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/alsa-stream/" --- # alsa-stream.c This is the source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) implementation for [ALSA][], used for live audio capture on Linux. ## Instructions **Also see these related items:** See [live-spot-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot-stream.md#live-spot-streamc). ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/alsa-stream.{c,h}_ **alsa-stream.h:** ```c /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK custom stream header. See alsa-stream.c. *------------------------------------------------------------------------------ */ typedef enum { STREAM_LATENCY_LOW, /* low latency, high CPU overhead */ STREAM_LATENCY_HIGH, /* higher latency, with lower CPU overhead */ } StreamLatency; SnsrStream streamFromALSA(const char *name, unsigned int rate, SnsrStreamMode mode, StreamLatency latency); ``` { data-search-exclude } **alsa-stream.c:** ```c /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK keyword spotting minimal example using a custom stream. *------------------------------------------------------------------------------ * SnsrStream ALSA (Linux audio) provider implementation. * Currently capture-only. *------------------------------------------------------------------------------ */ #include #include #include #include #include #include #include #include "alsa-stream.h" /* 15 ms at 16 kHz */ #define PERIOD_SIZE_LOW_LATENCY 240 /* 200 ms at 16 kHz */ #define PERIOD_SIZE_HIGH_LATENCY 3200 /* Minimum number of periods the buffer should include */ #define MIN_PERIOD_COUNT 5 /* Buffer size in ms */ #define MIN_BUFFER_MS 500 typedef struct { snd_pcm_t *in; const char *initErrorMsg; /* NULL if initialization was successful */ } ProviderData; /* This wrapper macro is used to simplify ALSA library error checking. * Commands are not executed if an error condition exists. */ #define AE(cmd)\ if (snsrStreamRC(b) == SNSR_RC_OK) {\ int r = snd_pcm_ ## cmd;\ if (r < 0) {\ snsrStream_setDetail(b, "ALSA error: %s", snd_strerror(r));\ snsrStream_setRC(b, SNSR_RC_ERROR);\ }\ } static SnsrRC streamOpen(SnsrStream b) { ProviderData *d = (ProviderData *)snsrStream_getData(b); if (!d->in) { if (d->initErrorMsg) snsrStream_setDetail(b, "%s", d->initErrorMsg); else snsrStream_setDetail(b, "Could not open ALSA device for capture."); return SNSR_RC_NOT_FOUND; } AE( prepare(d->in) ); return snsrStreamRC(b); } static SnsrRC streamClose(SnsrStream b) { ProviderData *d = (ProviderData *)snsrStream_getData(b); AE( drop(d->in) ); return snsrStreamRC(b); } static void streamRelease(SnsrStream b) { ProviderData *d = (ProviderData *)snsrStream_getData(b); AE( close(d->in) ); free((void *)d->initErrorMsg); free(d); } static size_t streamRead(SnsrStream b, void *buffer, size_t size) { ProviderData *d = (ProviderData *)snsrStream_getData(b); snd_pcm_uframes_t read, total = 0, want = size / sizeof(short); short *sbuff = buffer; if (snd_pcm_state(d->in) == SND_PCM_STATE_XRUN) { snsrStream_setRC(b, SNSR_RC_BUFFER_OVERRUN); return 0; } do { read = snd_pcm_readi(d->in, sbuff + total, want - total); if ((int)read < 0) read = snd_pcm_recover(d->in, read, 0); if ((int)read < 0) { snsrStream_setDetail(b, "ALSA read error: %s", snd_strerror((int)read)); snsrStream_setRC(b, SNSR_RC_ERROR); return 0; } total += read; } while (total < want); return total * sizeof(short); } static SnsrStream_Vmt ProviderDef = { "ALSA", &streamOpen, &streamClose, &streamRelease, &streamRead, NULL }; SnsrStream streamFromALSA(const char *name, unsigned int rate, SnsrStreamMode mode, StreamLatency latency) { SnsrStream b; ProviderData *d = (ProviderData *)malloc(sizeof(*d)); snd_pcm_t *h = NULL; snd_pcm_hw_params_t *p = NULL; int dir = 0; snd_pcm_uframes_t frames; if (!d) return NULL; memset(d, 0, sizeof(*d)); b = snsrStream_alloc(&ProviderDef, d, 1, 0); if (!b) { free(d); return NULL; } if (mode != SNSR_ST_MODE_READ) { snsrStream_setRC(b, SNSR_RC_INVALID_MODE); return b; } AE( open(&h, name, SND_PCM_STREAM_CAPTURE, 0) ); AE( hw_params_malloc(&p) ); AE( hw_params_any(h, p) ); AE( hw_params_set_access(h, p, SND_PCM_ACCESS_RW_INTERLEAVED) ); AE( hw_params_set_format(h, p, SND_PCM_FORMAT_S16_LE) ); AE( hw_params_set_channels(h, p, 1) ); AE( hw_params_set_rate(h, p, (unsigned)rate, 0) ); switch (latency) { case STREAM_LATENCY_LOW: frames = PERIOD_SIZE_LOW_LATENCY; break; case STREAM_LATENCY_HIGH: frames = PERIOD_SIZE_HIGH_LATENCY; break; } AE( hw_params_set_period_size_near(h, p, &frames, &dir) ); AE( hw_params_get_period_size(p, &frames, &dir) ); frames = MIN_PERIOD_COUNT * frames; if (frames < MIN_BUFFER_MS * rate / 1000.0 ) frames *= (int)(MIN_BUFFER_MS * rate / 1000.0 / frames + 0.5); AE( hw_params_set_buffer_size_near(h, p, &frames) ); AE( hw_params(h, p) ); snd_pcm_hw_params_free(p); if (snsrStreamRC(b) == SNSR_RC_OK) d->in = h; else if (h) snd_pcm_close(h); if (!d->in) d->initErrorMsg = strdup(snsrStreamErrorDetail(b)); return b; } ``` [ALSA]: http://www.alsa-project.org/main/index.php/ALSA_Library_API "Advanced Linux Sound Architecture" *[ALSA]: Advanced Linux Sound Architecture *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/c/aqs-stream.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/aqs-stream/" --- # aqs-stream.c This is the source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) implementation for [Audio Queue Services][], used for live audio capture on macOS and iOS. ## Instructions See [live-spot-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot-stream.md#live-spot-streamc). ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/aqs-stream.{c,h}_ **aqs-stream.h:** ```c /* Sensory Confidential * Copyright (C)2019-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK custom stream header. See aqs-stream.c. *------------------------------------------------------------------------------ */ typedef enum { STREAM_LATENCY_LOW, /* low latency, high CPU overhead */ STREAM_LATENCY_HIGH, /* higher latency, with lower CPU overhead */ } StreamLatency; SnsrStream streamFromAQS(unsigned int rate, SnsrStreamMode mode, StreamLatency latency); ``` { data-search-exclude } **aqs-stream.c:** ```c /* Sensory Confidential * Copyright (C)2018-2026 Sensory, Inc. https://sensory.com/ * *------------------------------------------------------------------------------ * SnsrStream provider for Audio Queue Services on Darwin. * Currently capture-only. *------------------------------------------------------------------------------ */ #include #include #include #include #include #include #include #include "aqs-stream.h" /* Initial size of the circular capture buffer. 500 ms at 16kHz */ #define CAPTURE_MINSIZE 16000 /* Maximum size of the circular capture buffer. 10 s at 16kHz */ #define CAPTURE_MAXSIZE 320000 #define PERIOD_LOW_LATENCY 0.015 #define PERIOD_HIGH_LATENCY 0.200 #define BUFFER_SIZE_SECONDS 2.0 /* 10 ms at 16 kHz */ #define MIN_BUFFER_SIZE 320 /* 5 s at 16 kHz */ #define MAX_BUFFER_SIZE 160000 #define MIN_BUFFER_COUNT 4 typedef struct { SnsrStream capture; /* Captured audio buffer */ const char *initErrorMsg; /* NULL if initialization ok */ AudioStreamBasicDescription dataFormat; /* recording format description */ AudioQueueRef queue; /* OS-level recording queue */ AudioQueueBufferRef *buffer; /* queue buffers */ pthread_mutex_t lock; /* protects capture stream */ pthread_cond_t notEmpty; /* signals capture stream */ size_t bufferCount; /* number of buffers in *buffer */ UInt32 bufferByteSize; /* size of one queue buffer */ unsigned isRunning:1; /* 0 to wind down recording */ } ProviderData; static SnsrRC ossErrorMessage(SnsrStream b, OSStatus s) { const char *msg; switch (s) { case kAudioServicesNoError: msg = NULL; case kAudioServicesUnsupportedPropertyError: msg = "The property is not supported."; break; case kAudioServicesBadPropertySizeError: msg = "The size of the property data was not correct."; break; case kAudioServicesBadSpecifierSizeError: msg = "The size of the specifier data was not correct."; break; case kAudioServicesSystemSoundClientTimedOutError: msg = "System sound client message timed out."; break; case kAudioServicesSystemSoundUnspecifiedError: default: snsrStream_setDetail(b, "An unspecified error occurred, code %i.", (int)s); return SNSR_RC_ERROR; } snsrStream_setDetail(b, "%s", msg); return SNSR_RC_ERROR; } static void audioCallback(void *privateData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime, UInt32 inNumPackets, const AudioStreamPacketDescription *inPacketDesc) { ProviderData *d = (ProviderData *)privateData; size_t written; if (!inNumPackets && d->dataFormat.mBytesPerPacket) inNumPackets = inBuffer->mAudioDataByteSize / d->dataFormat.mBytesPerPacket; if (inNumPackets) { pthread_mutex_lock(&d->lock); written = snsrStreamWrite(d->capture, inBuffer->mAudioData, d->dataFormat.mBytesPerPacket, inNumPackets); if (written < inNumPackets) snsrStream_setRC(d->capture, SNSR_RC_BUFFER_OVERRUN); pthread_cond_broadcast(&d->notEmpty); pthread_mutex_unlock(&d->lock); } if (d->isRunning) AudioQueueEnqueueBuffer(d->queue, inBuffer, 0, NULL); } static OSStatus audioInit(ProviderData *d, double sampleRate, double chunkSizeSeconds, double totalSizeSeconds) { AudioStreamBasicDescription *f = &d->dataFormat; OSStatus s; int i; /* Recording format: 16-bit LPCM at 16 kHz */ memset(f, 0, sizeof(*f)); f->mFormatID = kAudioFormatLinearPCM; f->mSampleRate = sampleRate; f->mChannelsPerFrame = 1; f->mBitsPerChannel = 16; f->mBytesPerPacket = f->mBytesPerFrame = f->mChannelsPerFrame * sizeof(SInt16); f->mFramesPerPacket = 1; f->mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; /* Create recording queue */ s = AudioQueueNewInput(f, audioCallback, d, NULL, kCFRunLoopCommonModes, 0, &d->queue); if (s != kAudioServicesNoError) return s; /* Derive appropriate audio queue buffer size */ d->bufferByteSize = (UInt32)(f->mSampleRate * f->mBytesPerPacket * chunkSizeSeconds); if (d->bufferByteSize > MAX_BUFFER_SIZE) d->bufferByteSize = MAX_BUFFER_SIZE; if (d->bufferByteSize < MIN_BUFFER_SIZE) d->bufferByteSize = MIN_BUFFER_SIZE; d->bufferCount = ceil(totalSizeSeconds / chunkSizeSeconds); if (d->bufferCount < MIN_BUFFER_COUNT) d->bufferCount = MIN_BUFFER_COUNT; /* Allocate audio buffers */ d->buffer = malloc(sizeof(*d->buffer) * d->bufferCount); for (i = 0; i < d->bufferCount && s == kAudioServicesNoError; i++) s = AudioQueueAllocateBuffer(d->queue, d->bufferByteSize, d->buffer + i); return s; } /*------------------------------------------------------------------------------ */ static SnsrRC streamOpen(SnsrStream b) { ProviderData *d = (ProviderData *)snsrStream_getData(b); OSStatus s; int i; if (d->initErrorMsg) { snsrStream_setDetail(b, "%s", d->initErrorMsg); return SNSR_RC_NOT_FOUND; } snsrStreamOpen(d->capture); s = kAudioServicesNoError; for (i = 0; i < d->bufferCount && s == kAudioServicesNoError; i++) s = AudioQueueEnqueueBuffer(d->queue, d->buffer[i], 0, NULL); if (s == kAudioServicesNoError) s = AudioQueueStart(d->queue, NULL); if (s != kAudioServicesNoError) return ossErrorMessage(b, s); d->isRunning = 1; return snsrStreamRC(b); } static SnsrRC streamClose(SnsrStream b) { ProviderData *d = (ProviderData *)snsrStream_getData(b); SnsrRC r; d->isRunning = 0; AudioQueueStop(d->queue, true); /* Flush the capture buffer */ r = snsrStreamRC(d->capture); snsrStreamSkip(d->capture, 1, CAPTURE_MAXSIZE); snsrStream_setRC(d->capture, SNSR_RC_OK); return r == SNSR_RC_OK? snsrStreamRC(b): r; } static void streamRelease(SnsrStream b) { ProviderData *d = (ProviderData *)snsrStream_getData(b); snsrRelease(d->capture); AudioQueueDispose(d->queue, true); pthread_mutex_destroy(&d->lock); pthread_cond_destroy(&d->notEmpty); free(d->buffer); free(d); } static size_t streamRead(SnsrStream b, void *buffer, size_t size) { SnsrRC r; ProviderData *d = (ProviderData *)snsrStream_getData(b); size_t read = 0; pthread_mutex_lock(&d->lock); if (snsrStreamRC(d->capture) != SNSR_RC_OK) { snsrStream_setRC(b, snsrStreamRC(d->capture)); } else { do { read += snsrStreamRead(d->capture, (char *)buffer + read, 1, size - read); r = snsrStreamRC(d->capture); } while ((r == SNSR_RC_OK || r == SNSR_RC_EOF) && read < size && !pthread_cond_wait(&d->notEmpty, &d->lock)); if (r != SNSR_RC_OK) { snsrStream_setRC(b, r); snsrStream_setDetail(b, "%s", snsrStreamErrorDetail(d->capture)); } else if (read < size) { snsrStream_setRC(b, SNSR_RC_EOF); } } pthread_mutex_unlock(&d->lock); return read; } static SnsrStream_Vmt ProviderDef = { "Darwin Audio Queue Services audio capture", &streamOpen, &streamClose, &streamRelease, &streamRead, NULL }; SnsrStream streamFromAQS(unsigned int rate, SnsrStreamMode mode, StreamLatency latency) { SnsrStream b; ProviderData *d = (ProviderData *)malloc(sizeof(*d)); OSStatus s; int r; if (!d) return NULL; memset(d, 0, sizeof(*d)); b = snsrStream_alloc(&ProviderDef, d, 1, 0); if (!b) { free(d); return NULL; } do { d->capture = snsrStreamFromBuffer(CAPTURE_MINSIZE, CAPTURE_MAXSIZE); if (!d->capture) { snsrStream_setRC(b, SNSR_RC_NO_MEMORY); break; } snsrRetain(d->capture); if (mode != SNSR_ST_MODE_READ) { snsrStream_setRC(b, SNSR_RC_INVALID_MODE); break; } /* Signalling and mutexes */ r = pthread_mutex_init(&d->lock, NULL); if (!r) r = pthread_cond_init(&d->notEmpty, NULL); if (r) { snsrStream_setRC(b, SNSR_RC_ERROR); snsrStream_setDetail(b, "%s", strerror(r)); break; } /* Allocate buffers */ s = audioInit(d, rate, latency == STREAM_LATENCY_LOW? PERIOD_LOW_LATENCY: PERIOD_HIGH_LATENCY, BUFFER_SIZE_SECONDS); if (s != kAudioServicesNoError) { snsrStream_setRC(b, ossErrorMessage(b, s)); break; } } while (0); if (snsrStreamRC(b) != SNSR_RC_OK) d->initErrorMsg = strdup(snsrStreamErrorDetail(b)); return b; } ``` [Audio Queue Services]: https://developer.apple.com/documentation/audiotoolbox/audio-queue-services "Audio Toolbox, Core Audio" *[API]: Application Programming Interface *[AQS]: Audio Queue Services, Apple's audio capture API on Darwin / macOS *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/c/data-stream.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/data-stream/" --- # data-stream.c This is the source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) implementation for memory data, similar to [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory). It's used in the [spot-data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data-stream.md#spot-data-streamc) example. ## Instructions See [spot-data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data-stream.md#spot-data-streamc). ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/data-stream.{c,h}_ **data-stream.h:** ```c /* Sensory Confidential * Copyright (C)2018-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK example of a custom stream, see data-stream.c. *------------------------------------------------------------------------------ */ SnsrStream streamFromData(void *data, size_t dataSize, SnsrStreamMode mode); ``` { data-search-exclude } **data-stream.c:** ```c /* Sensory Confidential * Copyright (C)2018-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK example of a custom stream, such as an audio stream * to get input from a custom audio driver (in a RTOS for example). * Similar streams are in samples wmme-stream.c and alsa-stream.c. * * NOTE: Normally it's best to use snsrStreamFromMemory(..) for a * stream of data, although this example would also work. *----------------------------------------------------------------------------- */ #include #include #include typedef struct { char *data; size_t dataSize; size_t index; } ProviderData; static SnsrRC streamOpen(SnsrStream stream) { ProviderData *instanceData = snsrStream_getData(stream); if (!instanceData->data) return SNSR_RC_ERROR; instanceData->index = 0; return SNSR_RC_OK; } static SnsrRC streamClose(SnsrStream stream) { ProviderData *instanceData = snsrStream_getData(stream); instanceData->index = 0; return SNSR_RC_OK; } static void streamRelease(SnsrStream stream) { ProviderData *instanceData = snsrStream_getData(stream); free(instanceData); } static size_t streamRead(SnsrStream stream, void *buffer, size_t readSize) { /* NOTE: For a live audio stream, if there is no data available, * this call should block until there is more data available. */ ProviderData *d = snsrStream_getData(stream); size_t available, read; read = readSize; available = d->dataSize - d->index; if (read > available) { read = available; /* Session will end with SNSR_RC_STREAM_END */ snsrStream_setRC(stream, SNSR_RC_EOF); } if (read) memcpy(buffer, d->data + d->index, read); d->index += read; return read; } static size_t streamWrite(SnsrStream stream, const void *buffer, size_t writeSize) { /* NOTE: For a live audio stream, implementing a streamWrite * would make no sense and this function should be removed. */ ProviderData *d = snsrStream_getData(stream); size_t available, written; written = writeSize; available = d->dataSize - d->index; if (written > available) { written = available; /* Session will end with SNSR_RC_STREAM_END */ snsrStream_setRC(stream, SNSR_RC_EOF); } if (written) memcpy(d->data + d->index, buffer, written); d->index += written; return written; } /* This is the interface any SnsrStream has to provide * (Virtual Method Table) */ static SnsrStream_Vmt methods = { "data", &streamOpen, &streamClose, &streamRelease, &streamRead, &streamWrite }; /* This is the 'constructor' for this kind of stream */ SnsrStream streamFromData(void *data, size_t dataSize, SnsrStreamMode mode) { SnsrStream dataStream; int readable = (mode == SNSR_ST_MODE_READ); int writeable = (mode == SNSR_ST_MODE_WRITE); /* The stream object has instance data (particular to this instance) * and virtual method pointers (particular to this type) * just like it would in C++ */ ProviderData *instanceData = malloc(sizeof(*instanceData)); memset(instanceData, 0, sizeof(*instanceData)); instanceData->data = data; instanceData->dataSize = dataSize; dataStream = snsrStream_alloc(&methods, instanceData, readable, writeable); if (data == NULL) snsrStream_setRC(dataStream, SNSR_RC_INVALID_ARG); return dataStream; } ``` *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/c/index.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/" --- # C examples The C sample programs are available in _sample/c/_ in the TrulyNatural installation directory. See _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/_ You can build the [sample code](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#c-examples-list) with [CMake](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#examples-cmake) or with [GNU Make](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#examples-make). ## Examples [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spotc) - Shows how to run a wake word recognizer on live audio captured from the default audio source. For a shorter teaching version you type yourself, see [Your first program](https://doc.sensory.com/tnl/7.8/getting-started/your-first-program.md#your-first-program). [live-spot-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot-stream.md#live-spot-streamc) - Runs a wake word recognizer on live audio captured using a custom audio stream, defined in [alsa-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/alsa-stream.md#alsa-streamc). [live-segment.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-segment.md#live-segmentc) - Runs a wake word recognizer on live audio, segments the speech following the wake word with a VAD, and then saves this audio snippet to a file. [push-audio.c](https://doc.sensory.com/tnl/7.8/api/sample/c/push-audio.md#push-audioc) - Runs a recognizer where the application pushes data through the recognition pipeline. Shows VAD audio processing for use with third-party recognizers such as keyword-to-search applications. [spot-data.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data.md#spot-datac) - Runs a small keyword spotter from code space. It uses a [custom memory allocator](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloctlsf) to avoid calls to the system heap allocator, and reads audio data from code space to avoid file system use. [spot-data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data-stream.md#spot-data-streamc) - This example runs a wake word from code space with a [custom audio stream](https://doc.sensory.com/tnl/7.8/api/sample/c/data-stream.md#data-streamc), using pull mode processing with [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run). It is a reasonable starting point for running on a small device with an RTOS. [alsa-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/alsa-stream.md#alsa-streamc) - Source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) implementation for [ALSA][], used for live audio capture on Linux. [aqs-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/aqs-stream.md#aqs-streamc) - Source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) implementation for [Audio Queue Services][], used for live audio capture on macOS and iOS. [wmme-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/wmme-stream.md#wmme-streamc) - Source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) implementation for [Windows Multimedia Extensions][], used for live audio capture on Windows. [data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/data-stream.md#data-streamc) - This is the source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) implementation for memory data, similar to [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory). It's used in the [spot-data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data-stream.md#spot-data-streamc) example. [snsr-edit.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-edit.md#snsr-editc) - Source for the [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) command-line tool. [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-evalc) - Source for the [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) command-line tool, and the `snsr-eval-subset` sample. [spot-convert.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-convert.md#spot-convertc) - Source for the [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) command-line tool. [spot-enroll.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-enroll.md#spot-enrollc) - Source for the [spot-enroll](https://doc.sensory.com/tnl/7.8/tools/spot-enroll.md#spot-enroll) command-line tool. [live-enroll.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-enroll.md#live-enrollc) - Source for the [live-enroll](https://doc.sensory.com/tnl/7.8/tools/live-enroll.md#live-enroll) command-line tool. ## Build with CMake We support building the code samples with [CMake][] on Linux, macOS, and Windows. This requires CMake 3.10 or later and a compiler toolchain. Open a terminal window and enter the commands below. ```sh cd ~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c cmake -S . -B build-sample cmake --build build-sample --parallel --config Release cmake --install build-sample ``` This installs the sample executables in the `bin/` subdirectory. ### CMakeLists.txt These are the `cmake` configuration files used to build the sample code. ### Details: CMakeLists.txt ```cmake # Sensory Confidential # Copyright (C)2024-2026 Sensory, Inc. https://sensory.com/ # # TrulyNatural SDK sample code build configuration # # Configure, build, and install these samples with: # # cmake -S . -B build-sample # cmake --build build-sample --parallel --config Release # cmake --install build-sample # # Then find the sample executables in build-sample/bin/ cmake_minimum_required(VERSION 3.10.0) if(POLICY CMP0177) cmake_policy(SET CMP0177 NEW) endif() project(SnsrSamples) list(APPEND CMAKE_MODULE_PATH "$ENV{HOME}/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9") include(SnsrLibrary) add_subdirectory(src) ``` ### Details: src/CMakeLists.txt ```cmake # Sensory Confidential # Copyright (C)2024-2026 Sensory, Inc. https://sensory.com/ # # This is not a stand-alone configuration. See by ../CMakeLists.txt set(SAMPLE_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../bin) set(MODEL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../model) set(SRC_GEN ${PROJECT_BINARY_DIR}/src) set(SPT_HBG spot-hbg-enUS-1.4.0-m) set(TPL_VAD tpl-vad-lvcsr-3.17.0) add_executable(live-enroll live-enroll.c) target_link_libraries(live-enroll SnsrLibraryOmitOSS) install(TARGETS live-enroll DESTINATION ${SAMPLE_BINARY_DIR}) add_executable(live-segment live-segment.c) target_link_libraries(live-segment SnsrLibraryOmitOSS) install(TARGETS live-segment DESTINATION ${SAMPLE_BINARY_DIR}) add_executable(live-spot live-spot.c) target_link_libraries(live-spot SnsrLibrary) install(TARGETS live-spot DESTINATION ${SAMPLE_BINARY_DIR}) if (APPLE) add_executable(live-spot-stream live-spot-stream.c aqs-stream.c) target_link_libraries(live-spot-stream SnsrLibrary) install(TARGETS live-spot-stream DESTINATION ${SAMPLE_BINARY_DIR}) elseif (UNIX) add_executable(live-spot-stream live-spot-stream.c alsa-stream.c) target_link_libraries(live-spot-stream SnsrLibrary) install(TARGETS live-spot-stream DESTINATION ${SAMPLE_BINARY_DIR}) elseif (WIN32) add_executable(live-spot-stream live-spot-stream.c wmme-stream.c) target_link_libraries(live-spot-stream SnsrLibrary) install(TARGETS live-spot-stream DESTINATION ${SAMPLE_BINARY_DIR}) endif () add_executable(push-audio push-audio.c) target_link_libraries(push-audio SnsrLibrary) install(TARGETS push-audio DESTINATION ${SAMPLE_BINARY_DIR}) add_executable(snsr-edit snsr-edit.c) target_link_libraries(snsr-edit SnsrLibrary) install(TARGETS snsr-edit DESTINATION ${SAMPLE_BINARY_DIR}) add_custom_command( OUTPUT ${SRC_GEN}/${SPT_HBG}.c COMMAND snsr-edit -c spot_hbg_enUS -t ${MODEL_DIR}/${SPT_HBG}.snsr DEPENDS snsr-edit ) add_custom_command( OUTPUT ${SRC_GEN}/${TPL_VAD}.c COMMAND snsr-edit -c tpl_vad_lvcsr -t ${MODEL_DIR}/${TPL_VAD}.snsr DEPENDS snsr-edit ) add_executable(snsr-eval snsr-eval.c ${SRC_GEN}/${TPL_VAD}.c) target_link_libraries(snsr-eval SnsrLibrary) install(TARGETS snsr-eval DESTINATION ${SAMPLE_BINARY_DIR}) add_custom_command( OUTPUT ${SRC_GEN}/snsr-custom-init.c COMMAND snsr-edit -it ${MODEL_DIR}/${SPT_HBG}.snsr DEPENDS snsr-edit ) add_executable(snsr-eval-subset snsr-eval.c ${SRC_GEN}/${TPL_VAD}.c ${SRC_GEN}/snsr-custom-init.c) target_link_libraries(snsr-eval-subset SnsrLibrary) target_compile_options(snsr-eval-subset PRIVATE -DSNSR_USE_SUBSET) install(TARGETS snsr-eval-subset DESTINATION ${SAMPLE_BINARY_DIR}) add_executable(spot-convert spot-convert.c) target_link_libraries(spot-convert SnsrLibraryOmitOSS) install(TARGETS spot-convert DESTINATION ${SAMPLE_BINARY_DIR}) add_executable(spot-data spot-data.c data.c ${SRC_GEN}/${SPT_HBG}.c) target_link_libraries(spot-data SnsrLibrary) install(TARGETS spot-data DESTINATION ${SAMPLE_BINARY_DIR}) add_executable(spot-data-stream spot-data-stream.c data-stream.c data.c ${SRC_GEN}/${SPT_HBG}.c) target_link_libraries(spot-data-stream SnsrLibrary) install(TARGETS spot-data-stream DESTINATION ${SAMPLE_BINARY_DIR}) add_executable(spot-enroll spot-enroll.c) target_link_libraries(spot-enroll SnsrLibraryOmitOSS) install(TARGETS spot-enroll DESTINATION ${SAMPLE_BINARY_DIR}) ``` ## Build with GNU Make We support building the code samples with [GNU Make][] on Linux and macOS only. This requires GNU Make 3.81 or later and a compiler toolchain. Open a terminal window and enter the commands below. ```sh cd ~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c make -j all ``` This installs the sample executables in the `bin/` subdirectory. If you run `make` without arguments the `Makefile` lists all available targets: ```console % make Make targets: make all # build all executables in ./bin make clean # remove build artifacts make debug # build all with debugging enabled make help # display this help message make test # run enrollment and spotting tests Building for macos from SDK root directory ../.. ``` Run the sample tests: ```console % make -j -s test Running test-enroll-0. Running test-enroll-1. Running test-enroll-2. Running test-enroll-3. Running test-convert-0. Running test-data-0. Running test-data-1. Running test-subset-0. ./build/out/dsp-pc38-3.4.0-op10-prod-net.bin: OK ./build/out/dsp-pc38-3.4.0-op10-prod-search.bin: OK ./build/out/dsp-search-check.h: OK Say the enrollment phrase (1/4) for "armadillo-1" Recording: 1.88 s Say the enrollment phrase (2/4) for "armadillo-1" Recording: 1.71 s Say the enrollment phrase (3/4) for "armadillo-1" with context, for example: " will it rain tomorrow?" Recording: 4.02 s Say the enrollment phrase (4/4) for "armadillo-1" with context, for example: " will it rain tomorrow?" Recording: 2.91 s Running test-push-0. Running test-push-1. SUCCESS: All tests passed. ``` ### Makefile This is the `make` configuration file used to build and test the sample code. ### Details: Makefile ```makefile # Sensory Confidential # Copyright (C)2015-2026 Sensory, Inc. https://sensory.com/ # # TrulyNatural SDK GNU make build script SNSR_ROOT := ../.. SNSR_EDIT = $(BIN_DIR)/snsr-edit # This Makefile is meant to run on the target platform. # Uncomment the following line if cross-compiling instead. # SNSR_EDIT = $(TOOL_DIR)/snsr-edit # OS-specific compiler defaults OS_NAME := $(shell uname -s) ifeq ($(OS_NAME),Linux) # Linux ARCH_NAME := $(shell $(CC) -dumpmachine) OS_CFLAGS := -O3 -fPIC -DNDEBUG OS_CFLAGS += -Wall -Werror OS_CFLAGS += -fdata-sections -ffunction-sections OS_LIBS := -lsnsr -lasound -lpthread -lm -ldl -lstdc++ OS_LDFLAGS+= -Wl,--gc-sections STATSIZE := stat -c %s else ifeq ($(OS_NAME),Darwin) # macOS ARCH_NAME := macos ARCH := $(shell uname -m) XCODE := /Applications/Xcode.app/Contents/Developer SYSROOT := $(XCODE)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk CC := $(XCODE)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang OS_ARCH := -arch $(ARCH) OS_CFLAGS := -O3 -fPIC -DNDEBUG OS_CFLAGS += $(OS_ARCH) OS_CFLAGS += -Wall -Werror OS_CFLAGS += -isysroot $(SYSROOT) OS_CFLAGS += -fdata-sections -ffunction-sections OS_LDFLAGS+= -isysroot $(SYSROOT) OS_LDFLAGS+= -dead_strip OS_LDFLAGS+= $(OS_ARCH) OS_LIBS := -lsnsr -framework AudioToolbox -framework CoreFoundation OS_LIBS += -framework Foundation -framework Accelerate OS_LIBS += -lm -lstdc++ STATSIZE := stat -f %z else $(error This operating system ($(OS_NAME)) is not supported) endif OS_CFLAGS += -I$(SNSR_ROOT)/include OS_LDFLAGS += -L$(SNSR_ROOT)/lib/$(ARCH_NAME) TARGET_DIR := . BIN_DIR = $(TARGET_DIR)/bin SRC_DIR = $(TARGET_DIR)/src OBJ_DIR = $(BUILD_DIR)/obj OUT_DIR = $(BUILD_DIR)/out BUILD_DIR = $(TARGET_DIR)/build TEST_DIR = $(TARGET_DIR)/test MODEL_DIR = $(SNSR_ROOT)/model DATA_DIR = $(SNSR_ROOT)/data TOOL_DIR = $(SNSR_ROOT)/bin # $(call audio-files,filename-prefix,index-list) # e.g. $(call audio-files,armadillo-6-,0 1 2) # returns a list of absolute paths to SDK enrollment test data audio-files = $(addsuffix .wav,$(addprefix $(DATA_DIR)/enrollments/$1,$2)) TEST_DATA := $(call audio-files,armadillo-1-,0 1 2 3 4 5) TEST_DATA += $(call audio-files,armadillo-6-,0 1 2 3 4 5) TEST_DATA += $(call audio-files,jackalope-1-,0 1 2 3 4 5) TEST_DATA += $(call audio-files,jackalope-4-,0 1 2 3 4 5) TEST_DATA += $(call audio-files,terminator-2-,0 1 2 3 4 5) TEST_DATA += $(call audio-files,terminator-6-,0 1 2 3 4 5) TEST_DATA += $(call audio-files,armadillo-1-,0-c 1-c 2-c 3-c 4-c 5-c) TEST_DATA += $(call audio-files,jackalope-1-,0-c 1-c 2-c 3-c 4-c 5-c) UDT_MODEL = $(MODEL_DIR)/udt-universal-3.67.1.0.snsr UDT_MODEL_5 = $(MODEL_DIR)/udt-enUS-5.1.1.9.snsr VTPL_MODEL = $(MODEL_DIR)/tpl-spot-vad-3.13.0.snsr HBG_MODEL_V = spot-hbg-enUS-1.4.0-m HBG_MODEL = $(MODEL_DIR)/$(HBG_MODEL_V).snsr VG_MODEL = $(MODEL_DIR)/spot-voicegenie-enUS-6.5.1-m.snsr BASE_MODEL = $(OUT_DIR)/enrolled-sv VAD_MODEL_V = tpl-vad-lvcsr-3.17.0 VAD_MODEL = $(MODEL_DIR)/$(VAD_MODEL_V).snsr .PHONY: all clean debug help test .PHONY: test-enroll-0 test-enroll-1 test-enroll-2 test-enroll-3 .PHONY: test-convert-0 .PHONY: test-push-0 test-push-1 define help Make targets: make all # build all executables in $(BIN_DIR) make clean # remove build artifacts make debug # build all with debugging enabled make help # display this help message make test # run enrollment and spotting tests Building for $(ARCH_NAME) from SDK root directory $(SNSR_ROOT) endef # Adjust test program verbosity # Resolves to -v, unless make is run with the -s (silent) flag. v = $(if $(findstring s,$(MAKEFLAGS)),,-v) # Default target help:; $(info $(help)) clean: rm -rf $(BIN_DIR) $(BUILD_DIR) $(OBJ_DIR) $(OUT_DIR) segmented-audio.wav rm -f $(SRC_DIR)/snsr-custom-init.c rm -f $(SRC_DIR)/$(HBG_MODEL_V).c $(SRC_DIR)/$(VAD_MODEL_V).c debug: all debug: CFLAGS=-O0 -g -UNDEBUG test: test-enroll-0 test-enroll-1 test-enroll-2 test-enroll-3\ test-convert-0 test-push-0 test-push-1 test-data-0 test-data-1\ test-subset-0 $(info SUCCESS: All tests passed.) # End-to-end UDT enrollment test test-enroll-0: $(BIN_DIR)/spot-enroll $(BIN_DIR)/snsr-eval | $(OUT_DIR) $(info Running $@.) $(BIN_DIR)/spot-enroll $v $v -t $(UDT_MODEL)\ -o $(BASE_MODEL)-0.snsr\ +armadillo-6 $(call audio-files,armadillo-6-,0 1 2 3)\ +jackalope-4 $(call audio-files,jackalope-4-,0 1 2 3)\ +terminator-2 $(call audio-files,terminator-2-,0 1 2 3)\ +terminator-6 $(call audio-files,terminator-6-,0 1 2 3)\ +armadillo-1 $(call audio-files,armadillo-1-,0 1)\ -c $(call audio-files,armadillo-1-,0-c)\ -c $(call audio-files,armadillo-1-,1-c)\ +jackalope-1 $(call audio-files,jackalope-1-,0 1)\ -c $(call audio-files,jackalope-1-,0-c)\ -c $(call audio-files,jackalope-1-,1-c) $(BIN_DIR)/snsr-eval -t $(BASE_MODEL)-0.snsr $(TEST_DATA)\ > $(OUT_DIR)/$@.txt diff $(OUT_DIR)/$@.txt $(TEST_DIR)/$@.txt\ || (echo ERROR: $@ validation failed; exit 100) # End-to-end UDT enrollment test, using adapted enrollment contexts test-enroll-1: $(BIN_DIR)/spot-enroll $(BIN_DIR)/snsr-eval | $(OUT_DIR) $(info Running $@.) $(BIN_DIR)/spot-enroll $v -t $(UDT_MODEL)\ -a $(OUT_DIR)/armadillo-6.snsr\ -o $(OUT_DIR)/enrolled-armadillo-6.snsr\ +armadillo-6 $(call audio-files,armadillo-6-,0 1 2 3) $(BIN_DIR)/spot-enroll $v -t $(UDT_MODEL)\ -a $(OUT_DIR)/jackalope-4.snsr\ -o $(OUT_DIR)/enrolled-jackalope-4.snsr\ +jackalope-4 $(call audio-files,jackalope-4-,0 1 2 3) $(BIN_DIR)/spot-enroll $v -t $(UDT_MODEL)\ -a $(OUT_DIR)/terminator-2.snsr\ -o $(OUT_DIR)/enrolled-terminator-2.snsr\ +terminator-2 $(call audio-files,terminator-2-,0 1 2 3) $(BIN_DIR)/spot-enroll $v -t $(UDT_MODEL)\ -a $(OUT_DIR)/terminator-6.snsr\ -o $(OUT_DIR)/enrolled-terminator-6.snsr\ +terminator-6 $(call audio-files,terminator-6-,0 1 2 3) $(BIN_DIR)/spot-enroll $v -t $(UDT_MODEL)\ -a $(OUT_DIR)/armadillo-1.snsr\ -o $(OUT_DIR)/enrolled-armadillo.snsr\ +armadillo-1 $(call audio-files,armadillo-1-,0 1)\ -c $(call audio-files,armadillo-1-,0-c)\ -c $(call audio-files,armadillo-1-,1-c) $(BIN_DIR)/spot-enroll $v -t $(UDT_MODEL)\ -a $(OUT_DIR)/jackalope-1.snsr\ -o $(OUT_DIR)/enrolled-jackalope-1.snsr\ +jackalope-1 $(call audio-files,jackalope-1-,0 1)\ -c $(call audio-files,jackalope-1-,0-c)\ -c $(call audio-files,jackalope-1-,1-c) $(BIN_DIR)/spot-enroll $v -t $(UDT_MODEL)\ -t $(OUT_DIR)/armadillo-6.snsr\ -t $(OUT_DIR)/jackalope-4.snsr\ -t $(OUT_DIR)/terminator-2.snsr\ -t $(OUT_DIR)/terminator-6.snsr\ -t $(OUT_DIR)/armadillo-1.snsr\ -t $(OUT_DIR)/jackalope-1.snsr\ -o $(BASE_MODEL)-1.snsr $(BIN_DIR)/snsr-eval -t $(BASE_MODEL)-1.snsr $(TEST_DATA)\ > $(OUT_DIR)/$@.txt diff $(OUT_DIR)/$@.txt $(TEST_DIR)/$@.txt >/dev/null\ || diff $(OUT_DIR)/$@.txt $(TEST_DIR)/$@-alt.txt >/dev/null\ || (echo ERROR: $@ validation failed; exit 101) # Live end-to-end UDT enrollment test. test-enroll-2: $(BIN_DIR)/live-enroll $(BIN_DIR)/snsr-eval | $(OUT_DIR) $(info Running $@.) $(BIN_DIR)/live-enroll $v $v -t $(UDT_MODEL)\ -o $(BASE_MODEL)-2.snsr\ +armadillo-1 $(call audio-files,armadillo-1-,0 1 0-c 1-c) $(BIN_DIR)/snsr-eval -t $(BASE_MODEL)-2.snsr $(TEST_DATA)\ > $(OUT_DIR)/$@.txt diff $(OUT_DIR)/$@.txt $(TEST_DIR)/$@.txt\ || (echo ERROR: $@ validation failed; exit 102) # Test old UDT model test-enroll-3: $(BIN_DIR)/spot-enroll $(BIN_DIR)/snsr-eval | $(OUT_DIR) $(info Running $@.) $(BIN_DIR)/spot-enroll $v $v -t $(UDT_MODEL_5)\ -o $(BASE_MODEL)-3.snsr\ +armadillo-1 $(call audio-files,armadillo-1-,0 1 2 3) $(BIN_DIR)/snsr-eval -t $(BASE_MODEL)-3.snsr $(TEST_DATA)\ > $(OUT_DIR)/$@.txt diff $(OUT_DIR)/$@.txt $(TEST_DIR)/$@.txt\ || (echo ERROR: $@ validation failed; exit 103) # Validate DSP conversion test-convert-0: $(BIN_DIR)/spot-convert | $(OUT_DIR) $(info Running $@.) $(BIN_DIR)/spot-convert -t $(HBG_MODEL) -p $(OUT_DIR)/dsp pc38 tail -10 $(OUT_DIR)/dsp-pc38-3.4.0-op10-prod-search.h\ > $(OUT_DIR)/dsp-search-check.h shasum -c $(TEST_DIR)/dsp-checksum.txt # Push audio samples instead of the default pull # Uses test-enroll-0 models test-push-0: test-enroll-0 $(BIN_DIR)/push-audio | $(OUT_DIR) $(info Running $@.) $(BIN_DIR)/push-audio $(BASE_MODEL)-0.snsr\ $(call audio-files,jackalope-4-,0)\ > $(OUT_DIR)/$@.txt diff $(OUT_DIR)/$@.txt $(TEST_DIR)/$@.txt\ || (echo ERROR: $@ validation failed; exit 104) # Push audio samples instead of the default pull # Uses test-enroll-0 models and the tpl-spot-vad-*.snsr template test-push-1: test-enroll-0 $(BIN_DIR)/push-audio $(SNSR_EDIT) | $(OUT_DIR) $(info Running $@.) $(SNSR_EDIT) -t $(VTPL_MODEL)\ -f 0 $(BASE_MODEL)-0.snsr -o $(OUT_DIR)/spot-vad.snsr $(BIN_DIR)/push-audio $(OUT_DIR)/spot-vad.snsr\ $(call audio-files,armadillo-1-,1-c)\ > $(OUT_DIR)/$@.txt diff $(OUT_DIR)/$@.txt $(TEST_DIR)/$@.txt\ || (echo ERROR: $@ validation failed; exit 105) test-data-0: $(BIN_DIR)/spot-data | $(OUT_DIR) $(info Running $@.) $(BIN_DIR)/spot-data > $(OUT_DIR)/$@.txt diff $(OUT_DIR)/$@.txt $(TEST_DIR)/$@.txt\ || (echo ERROR: $@ validation failed; exit 104) test-data-1: $(BIN_DIR)/spot-data-stream | $(OUT_DIR) $(info Running $@.) $(BIN_DIR)/spot-data-stream > $(OUT_DIR)/$@.txt diff $(OUT_DIR)/$@.txt $(TEST_DIR)/$@.txt\ || (echo ERROR: $@ validation failed; exit 104) test-subset-0: $(BIN_DIR)/snsr-eval-subset $(BIN_DIR)/snsr-eval | $(OUT_DIR) $(info Running $@.) test $(shell $(STATSIZE) $(BIN_DIR)/snsr-eval-subset) -lt \ $(shell $(STATSIZE) $(BIN_DIR)/snsr-eval) ||\ (echo ERROR: $@ size validation failed; exit 105) $(BIN_DIR)/snsr-eval-subset -t $(HBG_MODEL) /dev/null ||\ (echo ERROR: $@ validation failed; exit 106) $(BIN_DIR)/snsr-eval-subset -t $(VG_MODEL) /dev/null 2>&1 |\ grep SNSR_USE_SUBSET >/dev/null ||\ (echo ERROR: $@ validation failed; exit 107) # Create a rule for building name from source, in $(BIN_DIR) # $(call add-target-rule,name,source1.c source2.c ...) add-target-rule = $(eval $(call emit-target-rule,$1,$2)) define emit-target-rule all: $$(BIN_DIR)/$(strip $1) $$(BIN_DIR)/$(strip $1): $$(addprefix $$(OBJ_DIR)/,$(2:.c=.o)) | $$(BIN_DIR) $$(CC) $$(OS_LDFLAGS) $$(LDFLAGS) -o $$@ $$^ $$(OS_LIBS) $$(LIBS) endef # Command-line application targets $(call add-target-rule, spot-convert, spot-convert.c) $(call add-target-rule, snsr-edit, snsr-edit.c) $(call add-target-rule, spot-enroll, spot-enroll.c) $(call add-target-rule, snsr-eval, snsr-eval.c tpl-vad-lvcsr-3.17.0.c) $(call add-target-rule, snsr-eval-subset,\ snsr-eval-subset.c snsr-custom-init.c tpl-vad-lvcsr-3.17.0.c) $(call add-target-rule, live-enroll, live-enroll.c) $(call add-target-rule, live-segment, live-segment.c) $(call add-target-rule, live-spot, live-spot.c) $(call add-target-rule, push-audio, push-audio.c) $(call add-target-rule, spot-data,\ spot-data.c spot-hbg-enUS-1.4.0-m.c data.c) $(call add-target-rule, spot-data-stream,\ spot-data-stream.c data-stream.c spot-hbg-enUS-1.4.0-m.c data.c) ifeq ($(OS_NAME),Linux) # The custom stream sample uses ALSA on Linux. $(call add-target-rule, live-spot-stream, live-spot-stream.c alsa-stream.c) else ifeq ($(OS_NAME),Darwin) # The custom stream sample uses AQS on macOS. $(call add-target-rule, live-spot-stream, live-spot-stream.c aqs-stream.c) endif # Build object files from C sources $(OBJ_DIR)/%.o : $(SRC_DIR)/%.c | $(OBJ_DIR) $(CC) -c $(OS_CFLAGS) $(CFLAGS) -o $@ $< # spot-enroll doesn't use OSS modules $(OBJ_DIR)/spot-enroll.o : $(SRC_DIR)/spot-enroll.c | $(OBJ_DIR) $(CC) -DSNSR_OMIT_OSS_COMPONENTS -c $(OS_CFLAGS) $(CFLAGS) -o $@ $< # Create $(SRC_DIR)/snsr-custom-init.c using snsr-edit, # limit support to those modules needed for $(HBG_MODEL) $(SRC_DIR)/snsr-custom-init.c: $(SNSR_EDIT) $(SNSR_EDIT) -o $@ -vit $(HBG_MODEL) # Create $(SRC_DIR)/spot-hbg-enUS-*.c from the snsr model $(SRC_DIR)/$(HBG_MODEL_V).c: $(SNSR_EDIT) $(SNSR_EDIT) -o $@ -c spot_hbg_enUS -vt $(HBG_MODEL) # Create $(SRC_DIR)/tpl-vad-lvcsr-*.c from the snsr model $(SRC_DIR)/$(VAD_MODEL_V).c: $(SNSR_EDIT) $(SNSR_EDIT) -o $@ -c tpl_vad_lvcsr -vt $(VAD_MODEL) # Build snsr-eval-subset object files with -DSNSR_USE_SUBSET $(OBJ_DIR)/snsr-eval-subset.o: $(SRC_DIR)/snsr-eval.c | $(OBJ_DIR) $(CC) -c $(OS_CFLAGS) $(CFLAGS) -DSNSR_USE_SUBSET -o $@ $< # Create output directories $(BIN_DIR) $(BUILD_DIR) $(OBJ_DIR) $(OUT_DIR): mkdir -p $@ ``` [ALSA]: http://www.alsa-project.org/main/index.php/ALSA_Library_API "Advanced Linux Sound Architecture" [Audio Queue Services]: https://developer.apple.com/documentation/audiotoolbox/audio-queue-services "Audio Toolbox, Core Audio" [CMake]: https://cmake.org/ "CMake: A Powerful Software Build System" [GNU Make]: https://www.gnu.org/software/make/ "GNU Make build automation tool" [Windows Multimedia Extensions]: https://learn.microsoft.com/en-us/windows/win32/api/mmeapi/nf-mmeapi-waveinopen "waveInOpen" *[ALSA]: Advanced Linux Sound Architecture *[API]: Application Programming Interface *[AQS]: Audio Queue Services, Apple's audio capture API on Darwin / macOS *[RTOS]: Real-Time Operating System *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[VAD]: Voice Activity Detector *[WMME]: Windows Multimedia Extensions, the audio capture API on Windows --- source_path: "api/sample/c/live-enroll.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/live-enroll/" --- # live-enroll.c This is the source code for the [live-enroll](https://doc.sensory.com/tnl/7.8/tools/live-enroll.md#live-enroll) command-line tool. ## Instructions See [live-enroll](https://doc.sensory.com/tnl/7.8/tools/live-enroll.md#live-enroll). ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/live-enroll.c_ **live-enroll.c:** ```c /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK keyword spotting command-line enrollment utility, * using live audio from the default capture source. *------------------------------------------------------------------------------ */ #include #include #include #include #define DEFAULT_OUT "enrolled-sv.snsr" #define ENROLL_TASK_VERSION "~0.8.0 || 1.0.0" #ifdef _MSC_VER # define strdup _strdup # if _MSC_VER < 1900 # define snprintf _snprintf # endif #endif typedef struct { const char *enroll; /* optional enrollment context file name */ const char *model; /* enrolled phrase spotter output file name */ const char *prefix; /* audio capture file name prefix */ const char **user; /* pointer to users in argv[] */ char *phrase; /* enrollment phrase */ SnsrStream audio; /* audio stream handle */ int verbosity; /* incremented by the -v flag */ int userCount; /* number of users to enroll */ int currentUser; /* current user index */ int failCount; /* number of failed enrollment attempts */ } EnrollContext; static SnsrRC saveEnrollmentAudio(SnsrSession s, EnrollContext *e, const char *tag, int id) { SnsrStream out, enrollment; SnsrRC r; const char *dash, *user = NULL; const char *format = "%s%s%s-%s-%i.wav"; char *tmp; int len; dash = *e->prefix? "-": ""; snsrGetString(s, SNSR_USER, &user); r = snsrGetStream(s, SNSR_AUDIO_STREAM, &enrollment); if (r != SNSR_RC_OK) return r; if (snsrStreamRC(enrollment) != SNSR_RC_OK) return SNSR_RC_OK; len = snprintf(NULL, 0, format, e->prefix, dash, user, tag, id); if (len < 0) { snsrDescribeError(s, "snprintf() failed, rc = %i\n", len); return SNSR_RC_ERROR; } tmp = malloc(++len); if (!tmp) return SNSR_RC_NO_MEMORY; snprintf(tmp, len, format, e->prefix, dash, user, tag, id); out = snsrStreamFromAudioFile(tmp, "w", SNSR_ST_AF_DEFAULT); snsrRetain(out); snsrStreamCopy(out, enrollment, SIZE_MAX); if ((r = snsrStreamRC(out)) == SNSR_RC_EOF) r = SNSR_RC_OK; if (r != SNSR_RC_OK) snsrDescribeError(s, "%s", snsrStreamErrorDetail(out)); else if (e->verbosity > 0) { printf("Saved enrollment audio to %s\n", tmp); fflush(stdout); } snsrRelease(out); free(tmp); return r; } static SnsrRC nextEvent(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; const char *tag; if (e->currentUser >= e->userCount) return SNSR_RC_OK; tag = e->user[e->currentUser++] + 1; return snsrSetString(s, SNSR_USER, tag); } static SnsrRC passEvent(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; int id = 0; if (e->verbosity >= 1) { printf("Preliminary enrollment checks passed.\n"); fflush(stdout); } if (!e->prefix) return SNSR_RC_OK; snsrGetInt(s, SNSR_RES_ENROLLMENT_ID, &id); return saveEnrollmentAudio(s, e, "pass", id); } static SnsrRC pauseEvent(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; snsrStreamClose(e->audio); printf("\n"); fflush(stdout); return SNSR_RC_OK; } static SnsrRC resumeEvent(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; SnsrRC r; const char *tag; int count, target; int ctx; snsrStreamOpen(e->audio); snsrGetInt(s, SNSR_ENROLLMENT_TARGET, &target); snsrGetInt(s, SNSR_RES_ENROLLMENT_COUNT, &count); snsrGetInt(s, SNSR_ADD_CONTEXT, &ctx); r = snsrGetString(s, SNSR_USER, &tag); if (r == SNSR_RC_OK) { printf("\nSay %s (%i/%i) for \"%s\"", e->phrase, count + 1, target, tag); if (ctx) printf(" with context,\n for example: " "\" will it rain tomorrow?\""); printf("\n"); fflush(stdout); } return r; } static SnsrRC samplesEvent(SnsrSession s, const char *key, void *privateData) { double count; snsrGetDouble(s, SNSR_RES_SAMPLES, &count); printf("Recording: %6.2f s\r", count / 16000.0); fflush(stdout); return SNSR_RC_OK; } static SnsrRC doneEvent(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; SnsrRC r; SnsrStream model = NULL, out; size_t written; r = snsrGetStream(s, SNSR_MODEL_STREAM, &model); if (r != SNSR_RC_OK) return r; written = snsrStreamGetMeta(model, SNSR_ST_META_BYTES_WRITTEN); out = snsrStreamFromFileName(e->model, "w"); snsrStreamCopy(out, model, written); r = snsrStreamRC(out); if (r != SNSR_RC_OK) snsrDescribeError(s, "%s", snsrStreamErrorDetail(out)); snsrRelease(out); if (r == SNSR_RC_OK && e->verbosity >= 1) { printf("Enrolled model saved to \"%s\"\n", e->model); fflush(stdout); } if (r != SNSR_RC_OK) return r; return SNSR_RC_STOP; } static SnsrRC enrolledEvent(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; SnsrRC r; r = snsrSave(s, SNSR_FM_RUNTIME, snsrStreamFromFileName(e->enroll, "w")); if (r == SNSR_RC_OK && e->verbosity >= 1) { printf("Enrollment context saved to \"%s\"\n", e->enroll); fflush(stdout); } return r; } static SnsrRC printReason(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; const char *guidance, *reason; int pass = 0; double value = 0.0, threshold = 0.0; snsrGetInt(s, SNSR_RES_REASON_PASS, &pass); if (pass) return snsrRC(s); snsrGetString(s, SNSR_RES_REASON, &reason); snsrGetString(s, SNSR_RES_GUIDANCE, &guidance); snsrGetDouble(s, SNSR_RES_REASON_VALUE, &value); snsrGetDouble(s, SNSR_RES_REASON_THRESHOLD, &threshold); if (snsrRC(s) == SNSR_RC_OK) { fprintf(stderr, "This enrollment recording is not usable.\n"); fprintf(stderr, " Reason: %s", reason); if (e->verbosity >= 2) fprintf(stderr, " (%.2f, threshold is %.2f)", value, threshold); fprintf(stderr, "\n Fix: %s\n", guidance); fflush(stdout); } return snsrRC(s); } static SnsrRC failEvent(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; printReason(s, key, privateData); if (e->verbosity >= 3) { fprintf(stderr, "\nAll failed checks:\n"); fflush(stdout); snsrForEach(s, SNSR_REASON_LIST, snsrCallback(printReason, NULL, e)); } if (!e->prefix) return SNSR_RC_OK; return saveEnrollmentAudio(s, e, "fail", e->failCount++); } static SnsrRC progEvent(SnsrSession s, const char *key, void *privateData) { SnsrRC r = SNSR_RC_OK; EnrollContext *e = (EnrollContext *)privateData; if (e->verbosity >= 1) { double progress; r = snsrGetDouble(s, SNSR_RES_PERCENT_DONE, &progress); if (r == SNSR_RC_OK) { printf("\rAdapting: %3.0f%% complete.", progress); if (progress >= 100) printf("\n"); fflush(stdout); } } return r; } static void fatal(int rc, const char *format, ...) { va_list a; fprintf(stderr, "ERROR: "); va_start(a, format); vfprintf(stderr, format, a); va_end(a); fprintf(stderr, "\n"); exit(rc); } static const char *usageDetail = "Settings are strings used as keys to query or change task behavior.\n" "Most frequently used for enrollment is accuracy, which takes a value\n" "between 0 and 1.\n" "Refer to the " SNSR_NAME " SDK documentation for a complete list and\n" "descriptions of all supported settings.\n"; static void usage(const char *name) { SnsrSession s; const char *libInfo; fprintf(stderr, "Enrolls " SNSR_NAME " SDK wake words on live audio.\n\n"); fprintf(stderr, "usage: %s -t task [options] +user1 [+user2 ...] [file ...]\n" " options:\n" " -e enrollments : enrollment context output filename\n" " -o out : enrolled model output filename (default: " DEFAULT_OUT ")\n" " -p prefix : capture each enrollment to file as\n" " --{pass,fail}-.wav\n" " -s setting=value : override a task setting\n" " -t task : specify task filename (required)\n" " -v [-v [-v]] : increase verbosity\n", name); fprintf(stderr, "\nEnrollment audio is captured from the default microphone, unless\n" "the optional [file ...] arguments are supplied.\n"); fprintf(stderr, "\n%s", usageDetail); snsrNew(&s); snsrGetString(s, SNSR_LIBRARY_INFO, &libInfo); fprintf(stderr, "\n%s\n", libInfo); snsrRelease(s); exit(199); } /* Report model license keys. */ static void reportModelLicense(SnsrSession s, const char *modelfile, int verbose) { const char *msg = NULL; if (verbose > 1) { snsrGetString(s, SNSR_MODEL_LICENSE_EXPIRES, &msg); if (msg) fprintf(stderr, "\"%s\": %s.\n", modelfile, msg); } msg = NULL; snsrGetString(s, SNSR_MODEL_LICENSE_WARNING, &msg); if (msg) fprintf(stderr, "WARNING for model \"%s\": %s.\n", modelfile, msg); } /* Store the first enrollment phrase in e.phrase. */ static SnsrRC getVocab(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; SnsrRC r; const char *vocab; r = snsrGetString(s, SNSR_RES_TEXT, &vocab); if (r != SNSR_RC_OK) return r; free(e->phrase); e->phrase = strdup(vocab); return r; } int main(int argc, char *argv[]) { EnrollContext e; SnsrRC r; SnsrSession s; int i, o; const char *msg = NULL; extern char *optarg; extern int optind; #ifdef SNSR_USE_SECURITY_CHIP uint32_t *securityChipComms(uint32_t *in); snsrConfig(SNSR_CONFIG_SECURITY_CHIP, securityChipComms); #endif if (argc == 1) usage(argv[0]); r = snsrNew(&s); if (r != SNSR_RC_OK) fatal(r, s? snsrErrorDetail(s): snsrRCMessage(r)); e.currentUser = 0; e.enroll = NULL; e.phrase = strdup("the enrollment phrase"); e.prefix = NULL; e.model = DEFAULT_OUT; e.failCount = 0; e.userCount = 0; e.verbosity = 0; while ((o = getopt(argc, argv, "e:o:p:s:t:v?")) >= 0) { switch (o) { case 'e': e.enroll = optarg; break; case 'o': e.model = optarg; break; case 'p': e.prefix = optarg; r = snsrSetInt(s, SNSR_SAVE_ENROLLMENT_AUDIO, 1); if (r == SNSR_RC_NO_MODEL) fatal(r, "set -t task before -p prefix"); break; case 's': r = snsrSet(s, optarg); if (r == SNSR_RC_NO_MODEL) fatal(r, "set -t task before -s setting=value"); else if (r != SNSR_RC_OK) fatal(r, snsrErrorDetail(s)); break; case 't': snsrLoad(s, snsrStreamFromFileName(optarg, "r")); snsrRequire(s, SNSR_TASK_TYPE, SNSR_ENROLL); r = snsrRequire(s, SNSR_TASK_VERSION, ENROLL_TASK_VERSION); if (r != SNSR_RC_OK) fatal(r, snsrErrorDetail(s)); reportModelLicense(s, optarg, e.verbosity); break; case 'v': e.verbosity++; break; case '?': default: usage(argv[0]); } } if (optind == argc || argv[optind][0] != '+') usage(argv[0]); /* Report application license status */ if (e.verbosity > 1) { snsrGetString(s, SNSR_LICENSE_EXPIRES, &msg); if (msg) fprintf(stderr, "\"%s\": %s.\n", argv[0], msg); } msg = NULL; snsrGetString(s, SNSR_LICENSE_WARNING, &msg); if (msg) fprintf(stderr, "WARNING for \"%s\": %s.\n", argv[0], msg); r = snsrSetInt(s, SNSR_INTERACTIVE_MODE, 1); if (r == SNSR_RC_NO_MODEL) usage(argv[0]); snsrSetHandler(s, SNSR_NEXT_EVENT, snsrCallback(nextEvent, NULL, &e)); snsrSetHandler(s, SNSR_DONE_EVENT, snsrCallback(doneEvent, NULL, &e)); snsrSetHandler(s, SNSR_FAIL_EVENT, snsrCallback(failEvent, NULL, &e)); snsrSetHandler(s, SNSR_PASS_EVENT, snsrCallback(passEvent, NULL, &e)); snsrSetHandler(s, SNSR_PROG_EVENT, snsrCallback(progEvent, NULL, &e)); snsrSetHandler(s, SNSR_PAUSE_EVENT, snsrCallback(pauseEvent, NULL, &e)); snsrSetHandler(s, SNSR_RESUME_EVENT, snsrCallback(resumeEvent, NULL, &e)); snsrSetHandler(s, SNSR_SAMPLES_EVENT, snsrCallback(samplesEvent, NULL, &e)); if (e.enroll) snsrSetHandler(s, SNSR_ENROLLED_EVENT, snsrCallback(enrolledEvent, NULL, &e)); /* SNSR_VOCAB_LIST is supported for a subset of models only, ignore errors */ if (snsrRC(s) == SNSR_RC_OK) { snsrForEach(s, SNSR_VOCAB_LIST, snsrCallback(getVocab, NULL, &e)); snsrClearRC(s); } for (i = optind; i < argc && argv[i][0] == '+'; i++) ; e.user = (const char **)argv + optind; e.userCount = i - optind; if (i == argc) { e.audio = snsrStreamFromAudioDevice(SNSR_ST_AF_DEFAULT); } else { SnsrStream tmp; e.audio = snsrStreamFromString(""); for (; i < argc; i++) { tmp = snsrStreamFromFileName(argv[i], "r"); tmp = snsrStreamFromAudioStream(tmp, SNSR_ST_AF_DEFAULT); e.audio = snsrStreamFromStreams(e.audio, tmp); } } snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM, e.audio); r = snsrRun(s); if (r != SNSR_RC_OK && r != SNSR_RC_STOP) fatal(snsrRC(s), snsrErrorDetail(s)); free(e.phrase); snsrRelease(s); snsrTearDown(); return 0; } ``` *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/c/live-segment.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/live-segment/" --- # live-segment.c This example runs a wake word recognizer on live audio, segments the speech following the wake word with a VAD, and then saves this audio snippet to a file. ## Instructions [Build](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#examples-cmake) the sample code. In the same terminal window type the command after the `%`, then say "Voice Genie will it rain in Portland tomorrow?" ```console % ./bin/live-segment ../../model/tpl-spot-vad-3.13.0.snsr ../../model/spot-voicegenie-enUS-6.5.1-m.snsr Say will it rain in Portland tomorrow? Spotted "voicegenie", listening... VAD detected speech from 3150 ms to 5055 ms. Wrote recording to "vad-audio.wav". ``` `vad-audio.wav` contains the speech after the wake word. ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/live-segment.c_ **live-segment.c:** ```c /* Sensory Confidential * Copyright (C)2017-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK keyword spotter, runs trailing audio through * a voice activity detector and saves it to file. *------------------------------------------------------------------------------ */ #include #include /* Set INCLUDE_SPOT to 1 to include the trigger phrase in the audio output */ #define INCLUDE_SPOT 0 /* Output filename */ #define VAD_AUDIO_FILE "vad-audio.wav" /* Print an error message and exit. */ static void fatalError(int rc, const char *msg) { fprintf(stderr, "ERROR: %s\n", msg); exit(rc); } /* Result callback function, see snsrSetHandler() in main() below. */ static SnsrRC resultEvent(SnsrSession s, const char *key, void *privateData) { SnsrRC r; const char *phrase; r = snsrGetString(s, SNSR_RES_TEXT, &phrase); if (r == SNSR_RC_OK) { printf("Spotted \"%s\", listening...\n", phrase); fflush(stdout); } return r; } /* VAD segmentation callback - speech endpoint detected */ static SnsrRC endpointEvent(SnsrSession s, const char *key, void *privateData) { SnsrRC r; double begin, end; snsrGetDouble(s, SNSR_RES_BEGIN_MS, &begin); r = snsrGetDouble(s, SNSR_RES_END_MS, &end); if (r != SNSR_RC_OK) return r; printf("VAD detected speech from %.0f ms to %.f ms.\n", begin, end); return SNSR_RC_STOP; } int main(int argc, char *argv[]) { SnsrRC r; SnsrSession s; SnsrStream audio, out; const char *spotModel, *tmplModel; int testing = 0; if (argc < 3 || argc > 4) { fprintf(stderr, "usage: %s tmpl-vad-model spot-model [--test]\n", argv[0]); exit(1); } tmplModel = argv[1]; spotModel = argv[2]; testing = argc == 4; /* Create a new session handle. */ snsrNew(&s); /* Load and validate the spotter-vad template task file. */ snsrLoad(s, snsrStreamFromFileName(tmplModel, "r")); snsrRequire(s, SNSR_TASK_TYPE, SNSR_PHRASESPOT_VAD); /* Load the spotter into template slot 0. */ snsrSetStream(s, SNSR_SLOT_0, snsrStreamFromFileName(spotModel, "r")); /* If requested, include the trigger phrase in the audio output. */ snsrSetInt(s, SNSR_INCLUDE_LEADING_SILENCE, INCLUDE_SPOT); /* Register VAD endpoint callbacks. */ snsrSetHandler(s, SNSR_END_EVENT, snsrCallback(endpointEvent, NULL, NULL)); snsrSetHandler(s, SNSR_LIMIT_EVENT, snsrCallback(endpointEvent, NULL, NULL)); /* Register a result callback. Private data handle is used as a flag. */ snsrSetHandler(s, SNSR_RESULT_EVENT, snsrCallback(resultEvent, NULL, NULL)); /* Create an audio stream instance and attach it to the session. */ if (testing) { /* Read from stdin for testing. */ audio = snsrStreamFromFILE(stdin, SNSR_ST_MODE_READ); /* Reduce the trailing silence time-out, as test recordings have less than * 1000 ms of silence at the end */ snsrSetInt(s, SNSR_TRAILING_SILENCE, 500); /* Reduce VAD margins to the absolute minimum for testing only. This could * lead to small portions of the beginning and end of the audio being lost. * The recommendation is to use default values for production code. */ snsrSetInt(s, SNSR_BACKOFF, 0); snsrSetInt(s, SNSR_HOLD_OVER, 0); } else { /* live audio */ audio = snsrStreamFromAudioDevice(SNSR_ST_AF_DEFAULT); } snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM, audio); /* Set up the output stream. Speech-detected audio will be written to * this file. */ out = snsrStreamFromFileName(VAD_AUDIO_FILE, "w"); out = snsrStreamFromAudioStream(out, SNSR_ST_AF_DEFAULT); snsrSetStream(s, SNSR_SINK_AUDIO_PCM, out); printf("Say will it rain in Portland tomorrow?\n"); /* Main recognition loop. The endpoint handler will cause snsrRun() to * return SNSR_RC_STOP. Other return codes indicate an unexpected error. * Session errors remain until explicitly cleared: Any errors that occured * earlier will also be reported here. */ r = snsrRun(s); if (r != SNSR_RC_STOP) fatalError(r, snsrErrorDetail(s)); snsrRelease(s); printf("Wrote recording to \"%s\".\n", VAD_AUDIO_FILE); return 0; } ``` *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[VAD]: Voice Activity Detector --- source_path: "api/sample/c/live-spot-stream.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot-stream/" --- # live-spot-stream.c This example shows how to run a recognizer on live audio captured using a custom audio stream. **Also see these related items:** [alsa-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/alsa-stream.md#alsa-streamc), [aqs-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/aqs-stream.md#aqs-streamc), [wmme-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/wmme-stream.md#wmme-streamc), [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) ## Instructions 1. [Build](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#examples-cmake) the sample code. In the same terminal window type the command after the `%`, then say "hello blue genie": ```console % ./bin/live-spot-stream ../../model/spot-hbg-enUS-1.4.0-m.snsr Spotted "hello blue genie" at 5.34 seconds. ``` 2. This example works with any [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot) recognizer type, so let's create a concurrent combination of two wake words: ```console % ./bin/snsr-edit -vt ../../model/tpl-spot-concurrent-1.5.0.snsr \ -f 0 ../../model/spot-voicegenie-enUS-6.5.1-m.snsr \ -f 1 ../../model/spot-hbg-enUS-1.4.0-m.snsr \ -o spot-vg-or-hbg.snsr Output written to "spot-vg-or-hbg.snsr". ``` _spot-vg-or-hbg.snsr_ listens for both "voice genie" and "hello blue genie". Run the `live-spot-stream` example again and say one of these phrases: ```console % ./bin/live-spot-stream spot-vg-or-hbg.snsr Spotted "voicegenie" at 6.75 seconds. % ./bin/live-spot-stream spot-vg-or-hbg.snsr Spotted "hello blue genie" at 8.28 seconds. ``` 3. _(tnl)_ A VAD combined with either an LVCSR or STT model also works: ```console % ./bin/snsr-edit -vt ../../model/tpl-vad-lvcsr-3.17.0.snsr \ -f 0 ../../model/lvcsr-build-enUS-12.13.1-5MB.snsr \ -g phrases-stream "hello world; this is a test sentence; stop everything" \ -o vad-lvcsr.snsr Output written to "vad-lvcsr.snsr". % ./bin/live-spot-stream vad-lvcsr.snsr Spotted "this is a test sentence" at 4.46 seconds. % ./bin/live-spot-stream vad-lvcsr.snsr Spotted "" at 2.15 seconds. % ./bin/live-spot-stream vad-lvcsr.snsr Spotted "stop everything" at 1.88 seconds. ``` ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/live-spot-stream.c_ **live-spot-stream.c:** ```c /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ * * Keyword spotting minimal example using a custom audio stream. *------------------------------------------------------------------------------ */ #include #include /* Use the custom audio stream for this operating system */ #ifdef __linux__ # include "alsa-stream.h" # define streamFromCustom(r, m, l) streamFromALSA("default", r, m, l) #elif defined(__APPLE__) # include "aqs-stream.h" # define streamFromCustom(r, m, l) streamFromAQS(r, m, l) #elif defined(_WIN32) # include "wmme-stream.h" # define streamFromCustom(r, m, l) streamFromWMME(-1, r, m, l) #else # error Not supported on this platform. #endif /* Result callback function, see snsrSetHandler() in main() below. * Print the result text and the start time of the first spotted phrase. */ static SnsrRC resultEvent(SnsrSession s, const char *key, void *privateData) { SnsrRC r; const char *phrase; double begin; /* Retrieve the phrase text and start time from the session handle. */ snsrGetDouble(s, SNSR_RES_BEGIN_MS, &begin); r = snsrGetString(s, SNSR_RES_TEXT, &phrase); /* Quit early if an error occurred. */ if (r != SNSR_RC_OK) return r; printf("Spotted \"%s\" at %.2f seconds.\n", phrase, begin/1000.0); /* Returning a code other than SNSR_RC_OK instructs snsrRun() to return it. */ return SNSR_RC_STOP; } int main(int argc, char *argv[]) { SnsrRC r; SnsrSession s; if (argc != 2) { fprintf(stderr, "usage: %s spotter-model\n", argv[0]); exit(1); } /* Create a new session handle. */ snsrNew(&s); /* Load and validate the spotter model task file. */ snsrLoad(s, snsrStreamFromFileName(argv[1], "r")); snsrRequire(s, SNSR_TASK_TYPE, SNSR_PHRASESPOT); /* Create a live audio stream instance using a custom stream type, * then attach it to the session. */ snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM, streamFromCustom(16000, SNSR_ST_MODE_READ, STREAM_LATENCY_LOW)); /* Register a result callback. Private data handle is not used */ snsrSetHandler(s, SNSR_RESULT_EVENT, snsrCallback(resultEvent, NULL, NULL)); /* Main recognition loop. The result handler will cause snsrRun() to * return SNSR_RC_STOP. Other return codes indicate an unexpected error. * Session errors remain until explicitly cleared: Any errors that occured * earlier will also be reported here. */ r = snsrRun(s); if (r != SNSR_RC_STOP) fprintf(stderr, "ERROR: %s\n", snsrErrorDetail(s)); /* Release the session. This will also release the model and audio streams, * and the callback handler. No other references to these handles are held, * so their memory will be reclaimed. */ snsrRelease(s); return r; } ``` *[ALSA]: Advanced Linux Sound Architecture *[API]: Application Programming Interface *[AQS]: Audio Queue Services, Apple's audio capture API on Darwin / macOS *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[SDK]: Software Development Kit *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[VAD]: Voice Activity Detector *[WMME]: Windows Multimedia Extensions, the audio capture API on Windows --- source_path: "api/sample/c/live-spot.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot/" --- # live-spot.c New to the Session API? Start with [Your first program](https://doc.sensory.com/tnl/7.8/getting-started/your-first-program.md#your-first-program) (`first-spot.c`), then return here for the full sample. The same [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) + [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) pattern works for composed models built with [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit)—only the `.snsr` path changes (see step 3 below and [Command-line tools § Speech To Text](https://doc.sensory.com/tnl/7.8/getting-started/index.md#qs-stt)). This example shows how to run a recognizer on live audio captured from the default audio source. ## Instructions 1. [Build](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#examples-cmake) the sample code. In the same terminal window type the command after the `%`, then say "voice genie": ```console % ./bin/live-spot ../../model/spot-voicegenie-enUS-6.5.1-m.snsr Spotted "voicegenie" at 4.56 seconds. ``` 2. This example works with any [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot) recognizer type, so let's create a sequential combination of a wake word and a command set: ```console % ./bin/snsr-edit -vt ../../model/tpl-spot-sequential-1.5.0.snsr \ -f 0 ../../model/spot-voicegenie-enUS-6.5.1-m.snsr \ -f 1 ../../model/spot-music-enUS-1.2.0-m.snsr\ -o spot-vg-music.snsr Output written to "spot-vg-music.snsr". ``` _spot-vg-music.snsr_ listens for the wake word "voice genie". Once detected, it listens for up to five seconds for a small set of music player commands "play music", "stop music", "previous song", "next song", and "pause music". Run the `live-spot` example again and say some of the music commands. Then try "voice genie" followed by one of the commands again: ```console % ./bin/live-spot spot-vg-music.snsr Spotted "play_music" at 10.32 seconds. ``` 3. _(stt)_ A VAD combined with either an LVCSR or STT model also works: ```console % ./bin/snsr-edit -vt ../../model/tpl-vad-lvcsr-3.17.0.snsr \ -f 0 ../../model/stt-enUS-automotive-medium-2.3.15-pnc.snsr \ -o vad-stt.snsr Output written to "vad-stt.snsr". % ./bin/live-spot vad-stt.snsr Spotted "Hello world. This is a test sentence." at 2.61 seconds. ``` ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/live-spot.c_ **live-spot.c:** ```c /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK keyword spotting minimal example. *------------------------------------------------------------------------------ */ #include #include /* Result callback function, see snsrSetHandler() in main() below. * Print the result text and the start time of the first spotted phrase. */ static SnsrRC resultEvent(SnsrSession s, const char *key, void *privateData) { SnsrRC r; const char *phrase; double begin; /* Retrieve the phrase text and start time from the session handle. */ snsrGetDouble(s, SNSR_RES_BEGIN_MS, &begin); r = snsrGetString(s, SNSR_RES_TEXT, &phrase); /* Quit early if an error occurred. */ if (r != SNSR_RC_OK) return r; printf("Spotted \"%s\" at %.2f seconds.\n", phrase, begin/1000.0); /* Returning a code other than SNSR_RC_OK instructs snsrRun() to return it. */ return SNSR_RC_STOP; } int main(int argc, char *argv[]) { SnsrRC r; SnsrSession s; if (argc != 2) { fprintf(stderr, "usage: %s spotter-model\n", argv[0]); exit(1); } /* Create a new session handle. */ snsrNew(&s); /* Load and validate the spotter model task file. */ snsrLoad(s, snsrStreamFromFileName(argv[1], "r")); snsrRequire(s, SNSR_TASK_TYPE, SNSR_PHRASESPOT); /* Create a live audio stream instance and attach it to the session. */ snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM, snsrStreamFromAudioDevice(SNSR_ST_AF_DEFAULT)); /* Register a result callback. Private data handle is not used */ snsrSetHandler(s, SNSR_RESULT_EVENT, snsrCallback(resultEvent, NULL, NULL)); /* Main recognition loop. The result handler will cause snsrRun() to * return SNSR_RC_STOP. Other return codes indicate an unexpected error. * Session errors remain until explicitly cleared: Any errors that occured * earlier will also be reported here. */ r = snsrRun(s); if (r != SNSR_RC_STOP) fprintf(stderr, "ERROR: %s\n", snsrErrorDetail(s)); /* Release the session. This will also release the model and audio streams, * and the callback handler. No other references to these handles are held, * so their memory will be reclaimed. */ snsrRelease(s); return r; } ``` *[API]: Application Programming Interface *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[PNC]: Punctuation and Capitalization, an STT model variant that emits cased text with punctuation *[SDK]: Software Development Kit *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[VAD]: Voice Activity Detector --- source_path: "api/sample/c/push-audio.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/push-audio/" --- # push-audio.c This example runs a recognizer where the application pushes data through the recognition pipeline. Shows VAD audio processing for use with third-party recognizers such as keyword-to-search applications. ## Instructions 1. [Build](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#examples-cmake) the sample code. In the same terminal window type the command after the `%`, then say "voice genie" a number of times. Stop the executable with `^C`. ```console % ./bin/push-audio ../../model/spot-voicegenie-enUS-6.5.1-m.snsr Recognized "voicegenie" from sample 42960 to sample 53760. Recognized "voicegenie" from sample 90720 to sample 101280. Recognized "voicegenie" from sample 141360 to sample 155040. ^C ``` 2. Enroll a custom wake word. In the same terminal window type the command after the `%`, ```console % ./bin/spot-enroll -o spot-armadillo.snsr \ -vt ../../model/udt-universal-3.67.1.0.snsr \ +armadillo ../../data/enrollments/armadillo-1-{0,1,2,3}.wav Adapting: 100% complete. Enrolled model saved to "spot-armadillo.snsr" ``` 3. Run the `push-audio` example on the custom wake word with one of the example audio files: ```console % ./bin/push-audio spot-armadillo.snsr \ ../../data/enrollments/armadillo-1-0-c.wav Recognized "armadillo" from sample 5280 to sample 15120. ``` ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/push-audio.c_ **push-audio.c:** ```c /* Sensory Confidential * Copyright (C)2017-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK recognition from file example, where audio processing * is driven by the application, also known as push mode processing. *------------------------------------------------------------------------------ */ #include #include /* Ten second output ring buffer for optional VAD */ #define RING_BUFFER_SIZE 320000 /* Process 15 ms of 16-bit audio sampled at 16 kHz */ #define CHUNK_SIZE 480 #define TASKS_SUPPORTED\ SNSR_PHRASESPOT " 1.0.0;"\ SNSR_PHRASESPOT_VAD " 1.0.0;"\ SNSR_LVCSR " 1.0.0;"\ SNSR_VAD " 1.0.0" /* VAD endpoint event callback function. * Print the segmentation found, and return SNSR_RC_STOP to exit the main loop. */ static SnsrRC endEvent(SnsrSession s, const char *key, void *privateData) { double begin, end; snsrGetDouble(s, SNSR_RES_BEGIN_MS, &begin); snsrGetDouble(s, SNSR_RES_END_MS, &end); printf("VAD found audio from %.0f ms to %.0f ms.\n", begin, end); return SNSR_RC_STOP; } /* VAD detected silence, print a message and continue. */ static SnsrRC silenceEvent(SnsrSession s, const char *key, void *privateData) { printf("VAD detected silence. Listening for trigger.\n"); return SNSR_RC_OK; } /* Result callback function, see snsrSetHandler() in main() below. * Print the result hypothesis and the start and end sample indices * for this phrase. */ static SnsrRC resultEvent(SnsrSession s, const char *key, void *privateData) { SnsrRC r; const char *phrase; double begin, end; /* Retrieve the phrase text and alignments from the session handle */ snsrGetDouble(s, SNSR_RES_BEGIN_SAMPLE, &begin); snsrGetDouble(s, SNSR_RES_END_SAMPLE, &end); r = snsrGetString(s, SNSR_RES_TEXT, &phrase); /* Quit early if an error occurred. */ if (r != SNSR_RC_OK) return r; printf("Recognized \"%s\" from sample %.0f to sample %.0f.\n", phrase, begin, end); return SNSR_RC_OK; } /* Print error message and exit */ static void fatal(int rc, const char *format, ...) { va_list a; va_start(a, format); vfprintf(stderr, format, a); va_end(a); fprintf(stderr, "\n"); exit(rc); } int main(int argc, char *argv[]) { SnsrRC r; SnsrSession s; SnsrStream a, out = NULL; char buffer[CHUNK_SIZE]; size_t read; if (argc != 2 && argc != 3) fatal(255, "usage: %s model [wavefile]", argv[0]); /* Create a new session handle. */ snsrNew(&s); /* Load the model task file. */ snsrLoad(s, snsrStreamFromFileName(argv[1], "r")); /* Validate model types this application supports. */ r = snsrRequire(s, SNSR_TASK_TYPE_AND_VERSION_LIST, TASKS_SUPPORTED); if (r != SNSR_RC_OK) fatal(r, "ERROR: %s", snsrErrorDetail(s)); /* Check whether an output audio channel exists, wire it in if it does */ r = snsrSetStream(s, SNSR_SINK_AUDIO_PCM, NULL); if (r == SNSR_RC_DST_CHANNEL_NOT_FOUND) { snsrClearRC(s); } else { out = snsrStreamFromBuffer(RING_BUFFER_SIZE, RING_BUFFER_SIZE); snsrRetain(out); snsrSetStream(s, SNSR_SINK_AUDIO_PCM, out); /* Register VAD endpoint callbacks. */ snsrSetHandler(s, SNSR_END_EVENT, snsrCallback(endEvent, NULL, NULL)); snsrSetHandler(s, SNSR_LIMIT_EVENT, snsrCallback(endEvent, NULL, NULL)); snsrSetHandler(s, SNSR_SILENCE_EVENT, snsrCallback(silenceEvent, NULL, NULL)); } if (argc == 2) { /* Open a stream handle on the default microphone for live audio. */ a = snsrStreamFromAudioDevice(SNSR_ST_AF_DEFAULT); } else { /* Open a stream handle on the audio file. */ a = snsrStreamFromAudioFile(argv[2], "r", SNSR_ST_AF_DEFAULT); } /* Register a result callback. Private data handle is not used. */ r = snsrSetHandler(s, SNSR_RESULT_EVENT, snsrCallback(resultEvent, NULL, NULL)); /* Pure VAD models do support SNSR_RESULT_EVENTS, ignore the error */ if (r == SNSR_RC_SETTING_NOT_FOUND) snsrClearRC(s); /* Main recognition loop. */ do { /* Read from the audio stream into the temporary workspace. */ read = snsrStreamRead(a, buffer, sizeof(*buffer), CHUNK_SIZE); if (snsrStreamRC(a) != SNSR_RC_OK && snsrStreamRC(a) != SNSR_RC_EOF) fatal(snsrStreamRC(a), "ERROR: %s", snsrStreamErrorDetail(a)); /* Process one block of audio. */ r = snsrPush(s, SNSR_SOURCE_AUDIO_PCM, buffer, read); /* The VAD endpoint callback returns SNSR_RC_STOP. */ if (r == SNSR_RC_STOP) break; if (r != SNSR_RC_OK) fatal(r, "ERROR: %s", snsrErrorDetail(s)); /* If this is pipeline includes a voice activity detector, * read from the ring buffer stream, then process that output */ if (out) { #define VAD_CHUNK_SIZE 2400 short samples[VAD_CHUNK_SIZE]; size_t read = snsrStreamRead(out, samples, sizeof(*samples), VAD_CHUNK_SIZE); if (read > 0) { /* samples[] now contains read VAD audio samples. */ printf("Read %u samples from VAD stream.\n", (unsigned)read); } } } while (!snsrStreamAtEnd(a)); /* Flush internal audio ring buffer, stop any session threads */ r = snsrStop(s); /* Release the session. */ snsrRelease(s); /* Release the audio stream. */ snsrRelease(a); /* Release the ring buffer (VAD output) stream */ snsrRelease(out); /* POSIX process return code. */ return r == SNSR_RC_OK || r == SNSR_RC_STOP? 0: r; } ``` *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets *[VAD]: Voice Activity Detector --- source_path: "api/sample/c/snsr-edit.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-edit/" --- # snsr-edit.c This is the source code for the [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) command-line tool. ## Instructions See [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit). ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/snsr-edit.c_ **snsr-edit.c:** ```c /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK command-line model editing utility. *------------------------------------------------------------------------------ */ #include #include #include #include #define TASK_VERSION "~0.8.0 || 1.0.0" #define DEFAULT_INIT_FILENAME "snsr-custom-init.c"; static void fatal(SnsrSession s, int rc, const char *format, ...) { va_list a; fprintf(stderr, "ERROR: "); va_start(a, format); vfprintf(stderr, format, a); va_end(a); fprintf(stderr, "\n"); snsrRelease(s); exit(rc); } static const char *usageDetail = "Settings are strings used as keys to query or change task behavior.\n" "Most frequently used are operating-point for wake words and command sets,\n" "leading-silence and trailing-silence for VAD templates,\n" "partial-result-interval for LVCSR and STT, and stt-profile for STT models.\n" "Refer to the " SNSR_NAME " SDK documentation for a complete list and\n" "descriptions of all supported settings.\n"; static void usage(const char *name) { SnsrSession s; const char *libInfo; fprintf(stderr, "Edits/modifies " SNSR_NAME " SDK .snsr model files.\n\n"); fprintf(stderr, "usage: %s -t task [options]\n" " options:\n" " -C tag-identifier : emit C source to load model into RAM\n" " -c tag-identifier : emit C source to run model from code space\n" " -e setting filename : extract task setting/slot into filename\n" " -f setting filename : load filename into task setting/slot\n" " -g setting value : load string into task setting\n" " -i : emit custom initialization code\n" " -o out : output filename\n" " -p : prune unused settings to reduce model size\n" " -q setting : query a task setting\n" " -s setting=value : override a task setting\n" " -t task : specify task filename (required)\n" " -v [-v [-v]] : increase verbosity\n", name); fprintf(stderr, "\n%s", usageDetail); snsrNew(&s); snsrGetString(s, SNSR_LIBRARY_INFO, &libInfo); fprintf(stderr, "\n%s\n", libInfo); snsrRelease(s); exit(199); } /* Report command-line argument errors. */ static void quitOnError(SnsrSession s) { SnsrRC r = snsrRC(s); if (r == SNSR_RC_NO_MODEL) fatal(s, r, "set -t task before -f, -q, or -s options"); if (r != SNSR_RC_OK) fatal(s, r, "%s", snsrErrorDetail(s)); } /* Report model license keys. */ static void reportModelLicense(SnsrSession s, const char *modelfile, int verbose) { const char *msg = NULL; if (verbose > 1) { snsrGetString(s, SNSR_MODEL_LICENSE_EXPIRES, &msg); if (msg) fprintf(stderr, "\"%s\": %s.\n", modelfile, msg); } msg = NULL; snsrGetString(s, SNSR_MODEL_LICENSE_WARNING, &msg); if (msg) fprintf(stderr, "WARNING for model \"%s\": %s.\n", modelfile, msg); } int main(int argc, char *argv[]) { SnsrRC r; SnsrSession s; int customInit = 0, o, prune = 0, verbose = 0, useRAM = 0; const char *msg = NULL, *out = NULL, *task = NULL, *tag = NULL; char *outPath = NULL; extern char *optarg; extern int optind; #ifdef SNSR_USE_SECURITY_CHIP uint32_t *securityChipComms(uint32_t *in); snsrConfig(SNSR_CONFIG_SECURITY_CHIP, securityChipComms); #endif if (argc == 1) usage(argv[0]); r = snsrNew(&s); if (r != SNSR_RC_OK) fatal(s, r, "%s", s? snsrErrorDetail(s): snsrRCMessage(r)); snsrSetString(s, SNSR_PREPARE_SUBSET_INIT, NULL); snsrSetString(s, SNSR_PRUNE_SETTINGS, "no"); while ((o = getopt(argc, argv, "aC:c:e:f:g:io:pq:s:t:v?")) >= 0) { switch (o) { case 'C': useRAM = 1; case 'c': tag = optarg; break; case 'e': if (optind >= argc) usage(argv[0]); { SnsrStream slot, out; snsrGetStream(s, optarg, &slot); quitOnError(s); out = snsrStreamFromFileName(argv[optind], "w"); snsrRetain(out); if (verbose > 1) printf("Saving setting \"%s\" into \"%s\".\n", optarg, argv[optind]); snsrStreamCopy(out, slot, SIZE_MAX); if (snsrStreamRC(out) != SNSR_RC_EOF) fatal(s, snsrStreamRC(out), "%s", snsrStreamErrorDetail(out)); snsrRelease(out); optind++; } break; case 'f': if (optind >= argc) usage(argv[0]); if (verbose > 1) printf("Loading \"%s\" into setting \"%s\".\n", argv[optind], optarg); snsrSetStream(s, optarg, snsrStreamFromFileName(argv[optind++], "r")); quitOnError(s); reportModelLicense(s, argv[optind - 1], verbose); break; case 'g': if (optind >= argc) usage(argv[0]); if (verbose > 1) printf("Loading \"%s\" into setting \"%s\".\n", argv[optind], optarg); snsrSetStream(s, optarg, snsrStreamFromString(argv[optind++])); quitOnError(s); break; case 'i': customInit = 1; if (!out) out = DEFAULT_INIT_FILENAME; break; case 'o': out = optarg; break; case 'p': prune = 1; break; case 'q': { const char *strVal = NULL; if (snsrGetString(s, optarg, &strVal) == SNSR_RC_OK) { const char *q = strVal && strchr(strVal, ' ')? "\"": ""; printf("%s = %s%s%s\n", optarg, q, strVal, q); } quitOnError(s); break; } case 's': if (verbose > 2) printf("Applying setting \"%s\".\n", optarg); snsrSet(s, optarg); quitOnError(s); break; case 't': if (verbose > 1) printf("Loading \"%s\" as the template model.\n", optarg); snsrLoad(s, snsrStreamFromFileName(optarg, "r")); if (!task) task = optarg; quitOnError(s); reportModelLicense(s, optarg, verbose); break; case 'v': verbose++; break; case '?': default: usage(argv[0]); } } r = snsrRequire(s, SNSR_TASK_VERSION, TASK_VERSION); if (r == SNSR_RC_NO_MODEL || optind != argc) usage(argv[0]); /* Report application license status */ if (verbose > 1) { snsrGetString(s, SNSR_LICENSE_EXPIRES, &msg); if (msg) fprintf(stderr, "\"%s\": %s.\n", argv[0], msg); } msg = NULL; snsrGetString(s, SNSR_LICENSE_WARNING, &msg); if (msg) fprintf(stderr, "WARNING for \"%s\": %s.\n", argv[0], msg); snsrSetString(s, SNSR_MODEL_NAME, task); if (tag) { SnsrDataFormat fmt = SNSR_FM_SOURCE; if (!out) { char *t; if (!(out = outPath = malloc(strlen(task) + 3))) fatal(s, SNSR_RC_NO_MEMORY, "%s", snsrRCMessage(SNSR_RC_NO_MEMORY)); strcpy(outPath, task); if ((t = strrchr(outPath, '.'))) *t = '\0'; strcat(outPath, ".c"); if ((t = strrchr(outPath, '/')) || (t = strrchr(outPath, '\\'))) { *t = '\0'; out = t + 1; } } snsrSetString(s, SNSR_TAG_IDENTIFIER, tag); if (useRAM) fmt = SNSR_FM_SOURCE_RAM; else if (prune) fmt = SNSR_FM_SOURCE_PRUNED; r = snsrSave(s, fmt, snsrStreamFromFileName(out, "w")); } else if (customInit) { r = snsrSave(s, SNSR_FM_SUBSET_INIT, snsrStreamFromFileName(out, "w")); } else if (out) { r = snsrSave(s, prune? SNSR_FM_CONFIG_PRUNED: SNSR_FM_CONFIG, snsrStreamFromFileName(out, "w")); } if (r != SNSR_RC_OK) fatal(s, r, "%s", snsrErrorDetail(s)); if (out && verbose > 0) printf("Output written to \"%s\".\n", out); free(outPath); snsrRelease(s); snsrTearDown(); return 0; } ``` *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/c/snsr-eval.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval/" --- # snsr-eval.c This is the source code for the [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) command-line tool. The sample build also creates `snsr-eval-subset` from the same source. This is a version of `snsr-eval` that includes only the code modules required to run `spot-hbg-enUS-1.4.0-m.snsr`. It's built with `-DSNSR_USE_SUBSET` and `snsr-custom-init.c` created by [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit). See [src/CMakeLists.txt](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#cmakeliststxt) or [Makefile](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#makefile) for details. ## Instructions See [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval). ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/snsr-eval.c_ **snsr-eval.c:** ```c /* Sensory Confidential * * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK model evaluation command-line utility. *------------------------------------------------------------------------------ * This utility supports evaluation of many of the TrulyHandsfree/TrulyNatural * SDK task types. The source code is provided as a detailed example. * * For most use keyword spotting implementations the live-spot.c sample is a * better starting point. *------------------------------------------------------------------------------ */ #ifdef _WIN32 # include #endif #include #include #include #include #define TASKS_SUPPORTED\ SNSR_PHRASESPOT " ~0.5.0 || 1.0.0;"\ SNSR_PHRASESPOT_VAD " ~0.5.0 || 1.0.0;"\ SNSR_LVCSR " 1.0.0;"\ SNSR_VAD " 1.0.0;" \ SNSR_FEATURE " 1.0.0;" \ SNSR_FEATURE_PHRASESPOT " 1.0.0;"\ SNSR_FEATURE_LVCSR " 1.0.0;"\ SNSR_FEATURE_VAD " 1.0.0" #define DEFAULT_SAMPLE_RATE 16000 #define DEFAULT_FRAME_SIZE_MS 15 /* Used with the -i listFile batch processing option */ #define MAX_FILENAME_LENGTH 2048 #if defined(_MSC_VER) && (_MSC_VER < 1900) # define snprintf _snprintf #endif typedef struct { int nBest; /* Requested N-best results, usually 1 */ int verbose; /* Amount of detail resultEvent prints */ unsigned isPartial:1; /* 1 if this is a preliminary result */ unsigned isPhrase:1; /* 1 if this is a phrase-level iteration */ } ResultConfig; typedef struct { char *filename; /* partial output filename, e.g. out/ */ size_t prefix; /* filename directory path length */ size_t length; /* size of the filename buffer */ int verbose; } VadContext; static SnsrRC showAlignment(SnsrSession s, const char *key, void *privateData) { SnsrRC r; ResultConfig *config = (ResultConfig *)privateData; const char *phrase; const char *partial = config->isPartial? "P ": ""; double begin, end, score = -1.0, svscore; snsrGetString(s, SNSR_RES_TEXT, &phrase); snsrGetDouble(s, SNSR_RES_BEGIN_MS, &begin); snsrGetDouble(s, SNSR_RES_END_MS, &end); r = snsrGetDouble(s, SNSR_RES_SCORE, &score); if (r == SNSR_RC_SETTING_NOT_FOUND) snsrClearRC(s); r = snsrGetDouble(s, SNSR_RES_SV_SCORE, &svscore); if (r != SNSR_RC_OK) return r; if (config->nBest > 1 && config->isPhrase && !config->isPartial) { int count = 1, index = 0; snsrGetInt(s, SNSR_RES_COUNT, &count); snsrGetInt(s, SNSR_RES_INDEX, &index); printf("%2i/%i %6.0f %6.0f %s\n", index + 1, count, begin, end, phrase); } else if (config->verbose <= -2) { if (!config->isPartial) printf("%s\n", phrase); } else if (config->verbose == -1) { printf("%s%20s", phrase, config->isPartial? "\r": "\n"); } else if (config->verbose == 0) { printf("%s%6.0f %6.0f %s\n", partial, begin, end, phrase); } else { printf("%s%6.0f %6.0f (%.4g%s) %s\n", partial, begin, end, score >= 0? score: svscore, score >= 0? "": " sv", phrase); } fflush(stdout); return r; } static SnsrRC showAvailablePoint(SnsrSession s, const char *key, void *privateData) { SnsrRC r; int point, *first = (int *)privateData; r = snsrGetInt(s, SNSR_RES_AVAILABLE_POINT, &point); if (r == SNSR_RC_OK) { if (*first) printf("Available operating points: %i", point); else printf(", %i", point); *first = 0; } return r; } static SnsrRC showVocab(SnsrSession s, const char *key, void *privateData) { SnsrRC r; const char *text = NULL; int id = -1, *first = (int *)privateData; snsrGetInt(s, SNSR_RES_ID, &id); r = snsrGetString(s, SNSR_RES_TEXT, &text); if (r != SNSR_RC_OK) return r; if (*first) printf("Available vocabulary:\n"); printf(" %2i: \"%s\"\n", id, text); *first = 0; return r; } static SnsrRC entityIterator(SnsrSession s, const char *key, void *privateData) { const char *entity, *value; double score = 0; snsrGetDouble(s, SNSR_RES_NLU_ENTITY_SCORE, &score); snsrClearRC(s); /* Not all models support NLU scores, ignore errors */ snsrGetString(s, SNSR_RES_NLU_ENTITY_NAME, &entity); snsrGetString(s, SNSR_RES_NLU_ENTITY_VALUE, &value); printf("NLU entity: %s (%.4g) = %s\n", entity, score, value); return snsrRC(s); } static SnsrRC intentEvent(SnsrSession s, const char *key, void *privateData) { const char *intent, *value; double score = 0; snsrGetDouble(s, SNSR_RES_NLU_INTENT_SCORE, &score); snsrClearRC(s); /* Not all models support NLU scores, ignore errors */ snsrGetString(s, SNSR_RES_NLU_INTENT_NAME, &intent); snsrGetString(s, SNSR_RES_NLU_INTENT_VALUE, &value); printf("NLU intent: %s (%.4g) = %s\n", intent, score, value); return snsrForEach(s, SNSR_NLU_ENTITY_LIST, snsrCallback(entityIterator, NULL, privateData)); } static SnsrRC nluEvent(SnsrSession s, const char *key, void *privateData) { SnsrRC r; const char *name, *parentPath = (char *)privateData, *value; char *path; double score = 0; size_t pathLen = 0; int nluMax = 1, nBest = 1; snsrGetDouble(s, SNSR_RES_NLU_SLOT_SCORE, &score); snsrClearRC(s); /* Not all models support NLU scores, ignore errors */ snsrGetString(s, SNSR_RES_NLU_SLOT_NAME, &name); r = snsrGetString(s, SNSR_RES_NLU_SLOT_VALUE, &value); if (r != SNSR_RC_OK) return r; pathLen = strlen(SNSR_RES_NLU_SLOT_VALUE) + strlen(name) + 1; if (parentPath) pathLen += strlen(parentPath) + 1; path = malloc(pathLen); if (!path) return SNSR_RC_NO_MEMORY; if (!parentPath) { strcpy(path, SNSR_RES_NLU_SLOT_VALUE); strcat(path, name); } else { strcpy(path, parentPath); strcat(path, "."); strcat(path, name); } /* SNSR_NLU_RES_MAX introduced in 6.16.0, missing from older models */ r = snsrGetInt(s, SNSR_NLU_RES_MAX, &nluMax); if (r != SNSR_RC_OK) snsrClearRC(s); /* SNSR_RESULT_MAX introduced in 6.17.0, missing from older models */ r = snsrGetInt(s, SNSR_RESULT_MAX, &nBest); if (r != SNSR_RC_OK) snsrClearRC(s); if (nBest > 1 || nluMax > 1) { int nluIndex = 0, nluCount = 1, recIndex = 0, recCount = 0; snsrGetInt(s, SNSR_RES_COUNT, &recCount); snsrGetInt(s, SNSR_RES_INDEX, &recIndex); snsrClearRC(s); /* SNSR_RES_{COUNT,INDEX} not available before 6.17.0 */ snsrGetInt(s, SNSR_RES_NLU_COUNT, &nluCount); snsrGetInt(s, SNSR_RES_NLU_INDEX, &nluIndex); if (recCount > 1) { printf("%2i/%i NLU %2i/%i %s (%.4g) = %s\n", recIndex + 1, recCount, nluIndex + 1, nluCount, path, score, value); } else { printf("NLU %2i/%i %s (%.4g) = %s\n", nluIndex + 1, nluCount, path, score, value); } } else { printf("NLU %s (%.4g) = %s\n", path, score, value); } r = snsrForEach(s, SNSR_NLU_SLOT_LIST, snsrCallback(nluEvent, NULL, path)); free(path); return r; } static SnsrRC resultEvent(SnsrSession s, const char *key, void *privateData) { SnsrCallback c; ResultConfig *config = (ResultConfig *)privateData; const char *partial = config->isPartial? "P ": ""; /* Skip empty (LVCSR) results. */ if (config->nBest > 1) { const char *phrase = NULL; snsrGetString(s, SNSR_RES_TEXT, &phrase); if (phrase && !phrase[0]) return snsrRC(s); } if (config->verbose > 0 && !config->isPartial) { const char *domain = NULL; SnsrRC r = snsrGetString(s, SNSR_RES_DOMAIN, &domain); if (r != SNSR_RC_OK) snsrClearRC(s); else if (domain) printf("domain: %s\n", domain); } c = snsrCallback(showAlignment, NULL, privateData); snsrRetain(c); if (config->verbose > 1) printf("%sphrase:\n", partial); config->isPhrase = 1; snsrForEach(s, SNSR_PHRASE_LIST, c); config->isPhrase = 0; if (config->verbose > 1) { printf("%swords:\n", partial); snsrForEach(s, SNSR_WORD_LIST, c); } if (config->verbose > 2) { printf("%sphonemes:\n", partial); snsrForEach(s, SNSR_PHONE_LIST, c); } if (config->verbose > 1) { printf("\n"); fflush(stdout); } snsrRelease(c); return snsrRC(s); } /* The SNSR_ADAPT_STARTED_EVENT is called from a worker thread with * the SnsrSession argument set to NULL. */ static SnsrRC adaptStartedEvent(SnsrSession s, const char *key, void *privateData) { printf(" [%s] on worker thread\n", key); fflush(stdout); return SNSR_RC_OK; } /* Display events with sample time-stamps */ static SnsrRC showEvent(SnsrSession s, const char *key, void *privateData) { SnsrRC r; double samples, timestamp = 0; int rate = DEFAULT_SAMPLE_RATE; r = snsrGetInt(s, SNSR_SAMPLE_RATE, &rate); /* VAD task types do not include SNSR_SAMPLE_RATE support, use default */ if (r == SNSR_RC_SETTING_NOT_FOUND) snsrClearRC(s); r = snsrGetDouble(s, SNSR_RES_SAMPLES, &samples); if (r == SNSR_RC_OK) { timestamp = samples / rate * 1000; } else if (r == SNSR_RC_SETTING_NOT_FOUND) { double frames = 0; snsrClearRC(s); r = snsrGetDouble(s, SNSR_RES_FRAMES, &frames); timestamp = frames * DEFAULT_FRAME_SIZE_MS; } if (privateData) { const char *user = "(unknown)"; snsrGetString(s, SNSR_USER, &user); printf("%6.0f [%s] %s\n", timestamp, key, user); } else { printf("%6.0f [%s]\n", timestamp, key); } fflush(stdout); return snsrRC(s); } /* VAD start point detected */ static SnsrRC vadBeginEvent(SnsrSession s, const char *key, void *privateData) { VadContext *c = (VadContext *)privateData; if (c->verbose > 1) showEvent(s, key, NULL); if (c->filename) { SnsrStream out; double begin = 0; snsrGetDouble(s, SNSR_RES_BEGIN_MS, &begin); snprintf(c->filename + c->prefix, c->length - c->prefix, "%.0f.wav", begin); out = snsrStreamFromAudioFile(c->filename, "w", SNSR_ST_AF_DEFAULT); snsrSetStream(s, SNSR_SINK_AUDIO_PCM, out); snsrSetInt(s, SNSR_PASS_THROUGH, 1); if (c->verbose > 0) { printf("Saving VAD audio to \"%s\".\n", c->filename); fflush(stdout); } } return snsrRC(s); } /* VAD silence detected */ static SnsrRC vadSilenceEvent(SnsrSession s, const char *key, void *privateData) { VadContext *c = (VadContext *)privateData; if (c->verbose > 1) showEvent(s, key, NULL); return snsrRC(s); } /* Vad endpoint event */ static SnsrRC vadEndEvent(SnsrSession s, const char *key, void *privateData) { double begin, end; VadContext *c = (VadContext *)privateData; if (c->verbose > 0) { snsrGetDouble(s, SNSR_RES_BEGIN_MS, &begin); snsrGetDouble(s, SNSR_RES_END_MS, &end); printf("%6.0f %6.0f [%s] VAD speech region.\n", begin, end, key); fflush(stdout); } return snsrRC(s); } /* Optional SLM processing is about to start. */ static SnsrRC slmStartEvent(SnsrSession s, const char *key, void *privateData) { printf("SLM: "); fflush(stdout); return SNSR_RC_OK; } /* SLM partial result event, SNSR_RES_TEXT is the current next word prediction */ static SnsrRC slmPartialResultEvent(SnsrSession s, const char *key, void *privateData) { const char *txt = NULL; SnsrRC r = snsrGetString(s, SNSR_RES_TEXT, &txt); if (r != SNSR_RC_OK) return r; printf("%s", txt); fflush(stdout); return SNSR_RC_OK; } /* SLM final result event, SNSR_RES_TEXT is the entire result */ static SnsrRC slmResultEvent(SnsrSession s, const char *key, void *privateData) { printf("\n"); fflush(stdout); return SNSR_RC_OK; } static void fatal(SnsrSession s, int rc, const char *format, ...) { va_list a; fprintf(stderr, "ERROR: "); va_start(a, format); vfprintf(stderr, format, a); va_end(a); fprintf(stderr, "\n"); snsrRelease(s); exit(rc); } static void fatalSession(SnsrSession s) { fatal(s, snsrRC(s), "%s", snsrErrorDetail(s)); } static const char *usageDetail = "Use a filename of - to read headerless linear 16-bit PCM little-endian \n" "audio from stdin. If you don't specify any wave files, snsr-eval uses\n" "live audio captured from the default audio device.\n" "\n" "The -d and -o options are mutually exclusive. The output directory\n" "must be writable. Audio files created by VAD segmentation are named\n" " /.wav\n" "\n" "Settings are strings used as keys to query or change task behavior.\n" "Most frequently used are operating-point for wake words and command sets,\n" "leading-silence and trailing-silence for VAD templates,\n" "partial-result-interval for LVCSR and STT, and stt-profile for STT models.\n" "Refer to the " SNSR_NAME " SDK documentation for a complete list and\n" "descriptions of all supported settings.\n"; static void usage(const char *name) { SnsrSession s; const char *libInfo; fprintf(stderr, "Evaluates/runs " SNSR_NAME " SDK .snsr model files.\n\n"); fprintf(stderr, "usage: %s -t task [options] [wavefile ...]\n" " options:\n" " -a : Add tpl-vad-lvcsr to LVCSR and STT models\n" " -d directory : VAD audio output directory\n" " -f setting filename : load filename into task setting\n" " -g setting value : load string into task setting\n" " -i listFile : run evaluation on each filename" " in listFile\n" " -l [-l [-l]] : reduce verbosity\n" " -o out : output filename for VAD audio or" " listFile results\n" " -p [-p] : Enable pipeline profiling (experimental)\n" " -q setting : query a task setting\n" " -s setting=value : override a task setting\n" " -t task : specify task filename (required)\n" " -u filename : remove unused settings and save model" " to filename\n" " -v [-v [-v]] : increase verbosity\n", name); fprintf(stderr, "\n%s", usageDetail); snsrNew(&s); snsrGetString(s, SNSR_LIBRARY_INFO, &libInfo); fprintf(stderr, "\n%s\n", libInfo); snsrRelease(s); exit(199); } /* Report command-line argument errors. */ static void quitOnError(SnsrSession s) { SnsrRC r = snsrRC(s); if (r == SNSR_RC_NO_MODEL) fatal(s, r, "set -t task before -f or -s options"); if (r != SNSR_RC_OK) fatalSession(s); } /* Report model license keys. */ static void reportModelLicense(SnsrSession s, const char *modelfile, int verbose) { const char *msg = NULL; if (verbose > 1) { snsrGetString(s, SNSR_MODEL_LICENSE_EXPIRES, &msg); if (msg) fprintf(stderr, "\"%s\": %s.\n", modelfile, msg); } msg = NULL; snsrGetString(s, SNSR_MODEL_LICENSE_WARNING, &msg); if (msg) fprintf(stderr, "WARNING for model \"%s\": %s.\n", modelfile, msg); } /* Show CPU required to run the model in real time. This uses timing * information gathered while running model inference. */ static void showRealTimeFactor(SnsrSession s, const char *slot) { char path[SNSR_SETTING_SZ], *o; double cpuSeconds, rtf, samplesProcessed = 0; size_t len; int sampleRate; SnsrRC r; if (!slot) o = path; else { strcpy(path, slot); len = strlen(path); if (len && path[len - 1] != '.') strcat(path, "."); o = path + strlen(path); } snsrClearRC(s); strcpy(o, SNSR_RES_CPU_SECONDS_USED); snsrGetDouble(s, path, &cpuSeconds); strcpy(o, SNSR_RES_SAMPLES_PROCESSED); snsrGetDouble(s, path, &samplesProcessed); r = snsrGetInt(s, SNSR_SAMPLE_RATE, &sampleRate); if (r != SNSR_RC_OK || !samplesProcessed) { snsrClearRC(s); return; } rtf = cpuSeconds / samplesProcessed * sampleRate; if (slot && slot[0]) { printf("%5s: %8.0f samples, %6.3f seconds, %5.2f%% rtf\n", slot, samplesProcessed, cpuSeconds, rtf * 100); } else { printf("Total: %8.0f samples, %6.3f seconds, %5.2f%% rtf\n", samplesProcessed, cpuSeconds, rtf * 100); } } /* Reads one \n-terminated line from s int out, which has space for * at least outSize characters. * Skips empty lines (ones containing just \n) and lines starting with # * Strips a single trailing \r from out. */ static SnsrRC getNextLine(SnsrStream s, char *out, size_t outSize) { SnsrRC rc; size_t read; snsrRetain(s); for (;;) { read = snsrStreamGetDelim(s, out, outSize, '\n'); rc = snsrStreamRC(s); if (rc != SNSR_RC_OK) break; out[--read] = '\0'; /* strip trailing \n */ if (read > 0 && out[read - 1] == '\r') out[--read] = '\0'; if (read && out[0] != '#') break; } snsrRelease(s); return rc; } static SnsrRC batchEntityList(SnsrSession s, const char *key, void *privateData) { SnsrStream output = (SnsrStream)privateData; const char *name, *value; double score; snsrGetString(s, SNSR_RES_NLU_ENTITY_NAME, &name); snsrGetDouble(s, SNSR_RES_NLU_ENTITY_SCORE, &score); snsrGetString(s, SNSR_RES_NLU_ENTITY_VALUE, &value); snsrStreamPrint(output, "\t%s\t%.4g\t%s", name, score, value); return snsrRC(s); } static SnsrRC batchIntentEvent(SnsrSession s, const char *key, void *privateData) { SnsrStream output = (SnsrStream)privateData; const char *name, *value; double score; snsrGetString(s, SNSR_RES_NLU_INTENT_NAME, &name); snsrGetDouble(s, SNSR_RES_NLU_INTENT_SCORE, &score); snsrGetString(s, SNSR_RES_NLU_INTENT_VALUE, &value); snsrStreamPrint(output, "\t%s\t%4g\t%s", name, score, value); snsrForEach(s, SNSR_NLU_ENTITY_LIST, snsrCallback(batchEntityList, NULL, privateData)); return snsrRC(s); } static SnsrRC batchResultEvent(SnsrSession s, const char *key, void *privateData) { SnsrStream output = (SnsrStream)privateData; double begin, end, score; const char *hyp; snsrGetDouble(s, SNSR_RES_BEGIN_MS, &begin); snsrGetDouble(s, SNSR_RES_END_MS, &end); snsrGetDouble(s, SNSR_RES_SCORE, &score); snsrGetString(s, SNSR_RES_TEXT, &hyp); snsrStreamPrint(output, "\t%.0f\t%.0f\t%.6g\t%s", begin, end, score, hyp); return snsrRC(s); } /* Batch processing mode, one audio filename per line in listFile */ static SnsrRC batch(SnsrSession s, const char *listFile, const char *outFile) { char fileName[MAX_FILENAME_LENGTH]; SnsrStream ls = NULL; SnsrStream out, nlu, result; int fileIndex = 0, fileCount = 0; SnsrRC r = SNSR_RC_OK; /* Count the number of lines in listFile */ ls = snsrStreamFromFileName(listFile, "r"); snsrRetain(ls); while ((r = getNextLine(ls, fileName, sizeof(fileName))) == SNSR_RC_OK) fileCount++; if (r != SNSR_RC_EOF) fatal(s, r, "\"%s\": %s", listFile, snsrStreamErrorDetail(ls)); snsrRelease(ls); /* Open output stream */ if (outFile) out = snsrStreamFromFileName(outFile, "w"); else out = snsrStreamFromFILE(stdout, SNSR_ST_MODE_WRITE); /* In-memory result and NLU streams, we'll copy these to the output */ result = snsrStreamFromBuffer(1<<10, 1<<20); nlu = snsrStreamFromBuffer(1<<10, 1<<20); /* Install result handlers for batch mode processing */ snsrSetHandler(s, SNSR_RESULT_EVENT, snsrCallback(batchResultEvent, NULL, result)); snsrSetHandler(s, SNSR_NLU_INTENT_EVENT, snsrCallback(batchIntentEvent, NULL, nlu)); /* Iterate over all audio files in listFile */ ls = snsrStreamFromFileName(listFile, "r"); snsrRetain(ls); while ((r = getNextLine(ls, fileName, sizeof(fileName))) == SNSR_RC_OK) { fileIndex++; if (outFile) { printf("\rProcessing file %i of %i, %.2f%% ", fileIndex, fileCount, (double)fileIndex / fileCount * 100); fflush(stdout); } snsrReset(s); snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM, snsrStreamFromAudioFile(fileName, "r", SNSR_ST_AF_DEFAULT)); r = snsrRun(s); if (r != SNSR_RC_OK && r != SNSR_RC_STREAM_END) { fprintf(stderr, "\nWARNING: %s index %i: %s\n", listFile, fileIndex, snsrErrorDetail(s)); snsrStreamSkip(result, 1, SIZE_MAX); snsrStreamSkip(nlu, 1, SIZE_MAX); continue; } snsrStreamPrint(out, "%i\t%s", fileIndex, fileName); snsrStreamCopy(out, result, SIZE_MAX); snsrStreamCopy(out, nlu, SIZE_MAX); snsrStreamPrint(out, "\n"); } if (r == SNSR_RC_EOF) r = SNSR_RC_OK; snsrRelease(ls); snsrRelease(nlu); snsrRelease(out); snsrRelease(result); if (outFile) printf("\n"); return r; } int main(int argc, char *argv[]) { SnsrRC r; SnsrSession s; SnsrStream tmp, audio = NULL; int i, o, profile = 0; int vadAdded = 0, verbose = 0; const char *dir = NULL, *list = NULL, *msg = NULL, *out = NULL, *save = NULL; extern char *optarg; extern int optind; ResultConfig full = {1, 0, 0, 0}, partial = {1, 0, 1, 0}; VadContext vadContext = {NULL, 0, 0}; #ifdef SNSR_USE_SECURITY_CHIP uint32_t *securityChipComms(uint32_t *in); snsrConfig(SNSR_CONFIG_SECURITY_CHIP, securityChipComms); #endif #ifdef _WIN32 SetConsoleOutputCP(CP_UTF8); #endif if (argc == 1) usage(argv[0]); r = snsrNew(&s); if (r != SNSR_RC_OK) fatal(s, r, "%s", s? snsrErrorDetail(s): snsrRCMessage(r)); while ((o = getopt(argc, argv, "ad:f:g:i:lo:pq:s:t:u:v?")) >= 0) { switch (o) { case 'a': { /* Load VAD model compiled into this executable */ extern SnsrCodeModel tpl_vad_lvcsr; const char *taskType = ""; r = snsrGetString(s, SNSR_TASK_TYPE, &taskType); if (r != SNSR_RC_NO_MODEL) fatal(s, r, "set the -a option before -t, " "for example %s -at task", argv[0]); snsrClearRC(s); snsrLoad(s, snsrStreamFromCode(tpl_vad_lvcsr)); quitOnError(s); vadAdded = 1; break; } case 'd': dir = optarg; break; case 'f': if (optind >= argc) usage(argv[0]); snsrSetStream(s, optarg, snsrStreamFromFileName(argv[optind++], "r")); quitOnError(s); reportModelLicense(s, argv[optind - 1], verbose); break; case 'g': if (optind >= argc) usage(argv[0]); snsrSetStream(s, optarg, snsrStreamFromString(argv[optind++])); quitOnError(s); break; case 'i': list = optarg; break; case 'l': verbose--; break; case 'o': out = optarg; break; case 'p': profile++; break; case 'q': { const char *strVal = NULL; if (snsrGetString(s, optarg, &strVal) == SNSR_RC_OK) { const char *q = strVal && strchr(strVal, ' ')? "\"": ""; printf("%s = %s%s%s\n", optarg, q, strVal, q); } quitOnError(s); break; } case 's': snsrSet(s, optarg); quitOnError(s); break; case 't': if (vadAdded) { /* The tpl-vad-lvcsr expects an LVCSR or STT model in slot 0 */ snsrSetStream(s, SNSR_SLOT_0, snsrStreamFromFileName(optarg, "r")); vadAdded = 0; } else { snsrLoad(s, snsrStreamFromFileName(optarg, "r")); } quitOnError(s); reportModelLicense(s, optarg, verbose); break; case 'u': snsrSetString(s, SNSR_PRUNE_SETTINGS, "yes"); save = optarg; break; case 'v': verbose++; break; case '?': default: usage(argv[0]); } } r = snsrRequire(s, SNSR_TASK_TYPE_AND_VERSION_LIST, TASKS_SUPPORTED); if (r == SNSR_RC_NO_MODEL) usage(argv[0]); else if (r != SNSR_RC_OK) fatalSession(s); if (list) { if (optind != argc) fatal(s, SNSR_RC_INVALID_ARG, "Use \"-i listfile\" or audio files " "on the command line, but not both."); r = batch(s, list, out); if (r != SNSR_RC_OK && r != SNSR_RC_STREAM_END) fatalSession(s); snsrRelease(s); snsrTearDown(); return 0; } if (out && dir) fatal(s, SNSR_RC_INVALID_ARG, "The -d and -o options are multually exclusive."); /* Report application license status */ if (verbose > 1) { snsrGetString(s, SNSR_LICENSE_EXPIRES, &msg); if (msg) fprintf(stderr, "\"%s\": %s.\n", argv[0], msg); } msg = NULL; snsrGetString(s, SNSR_LICENSE_WARNING, &msg); if (msg) fprintf(stderr, "WARNING for \"%s\": %s.\n", argv[0], msg); r = snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM, NULL); snsrClearRC(s); if (r == SNSR_RC_OK) { /* No audio files provided, use live audio from the * default capture device */ if (optind == argc) { const char *taskType = ""; snsrGetString(s, SNSR_TASK_TYPE, &taskType); if (!strcmp(taskType, SNSR_LVCSR)) fatal(s, SNSR_RC_ERROR, "With live audio LVCSR and STT models require " "a VAD. You can add one with the -a flag."); audio = snsrStreamFromAudioDevice(SNSR_ST_AF_DEFAULT); if (verbose > 0) { printf("Using live audio from default capture device. ^C to stop.\n"); fflush(stdout); } } else { /* Create stream concatenation of all the audio files */ audio = snsrStreamFromString(""); for (i = optind; i < argc; i++) { if (argv[i][0] == '-' && argv[i][1] == '\0') { tmp = snsrStreamFromFILE(stdin, SNSR_ST_MODE_READ); } else { tmp = snsrStreamFromAudioFile(argv[i], "r", SNSR_ST_AF_DEFAULT); } audio = snsrStreamFromStreams(audio, tmp); } } /* Wire up the audio input stream. */ snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM, audio); } else { /* SNSR_SOURCE_AUDIO_PCM not found, try feature-stream */ r = snsrSetStream(s, SNSR_SOURCE_FEATURE, NULL); snsrClearRC(s); if (r == SNSR_RC_OK) { SnsrStream feature; feature = snsrStreamFromString(""); for (i = optind; i < argc; i++) { SnsrStream tmp = snsrStreamFromFileName(argv[i], "r"); feature = snsrStreamFromStreams(feature, tmp); } r = snsrSetStream(s, SNSR_SOURCE_FEATURE, feature); } else r = SNSR_RC_OK; } /* The SNSR_OPERATING_POINT setting was introduced with 5.0.0-beta.10 */ if (verbose > 1 && snsrRC(s) == SNSR_RC_OK) { int first = 1, point = 0; r = snsrGetInt(s, SNSR_OPERATING_POINT, &point); if (r == SNSR_RC_SETTING_NOT_FOUND || r == SNSR_RC_VALUE_NOT_SET) { snsrClearRC(s); } else { printf("Using operating point %i.\n", point); snsrForEach(s, SNSR_OPERATING_POINT_LIST, snsrCallback(showAvailablePoint, NULL, &first)); printf(".\n"); fflush(stdout); } } /* The SNSR_VOCAB_LIST setting was introduced with 6.7.0. */ if (verbose > 1 && snsrRC(s) == SNSR_RC_OK) { int first = 1; snsrForEach(s, SNSR_VOCAB_LIST, snsrCallback(showVocab, NULL, &first)); snsrClearRC(s); } /* Wire up the optional audio output stream. */ r = snsrSetStream(s, SNSR_SINK_AUDIO_PCM, NULL); if (r == SNSR_RC_DST_CHANNEL_NOT_FOUND) { r = SNSR_RC_OK; snsrClearRC(s); } else if (out) { r = snsrSetStream(s, SNSR_SINK_AUDIO_PCM, snsrStreamFromAudioFile(out, "w", SNSR_ST_AF_DEFAULT)); } else { /* No file specified, turn off VAD audio output. */ r = snsrSetInt(s, SNSR_PASS_THROUGH, 0); } /* Wire up the optional feature output stream. */ if (r == SNSR_RC_OK) { r = snsrSetStream(s, SNSR_SINK_FEATURE, NULL); if (r == SNSR_RC_DST_CHANNEL_NOT_FOUND) { r = SNSR_RC_OK; snsrClearRC(s); } else if (out) { r = snsrSetStream(s, SNSR_SINK_FEATURE, snsrStreamFromFileName(out, "w")); } else { /* No file specified, turn off VAD feature output. */ r = snsrSetInt(s, SNSR_PASS_THROUGH, 0); } } if (r != SNSR_RC_OK) fatalSession(s); /* SNSR_RESULT_MAX introduced in 6.17.0, missing from older models */ r = snsrGetInt(s, SNSR_RESULT_MAX, &full.nBest); if (r != SNSR_RC_OK) snsrClearRC(s); /* Handle recognition results. */ full.verbose = verbose; r = snsrSetHandler(s, SNSR_RESULT_EVENT, snsrCallback(resultEvent, NULL, &full)); /* VAD task types do not include SNSR_RESULT_EVENT support */ if (r == SNSR_RC_SETTING_NOT_FOUND) snsrClearRC(s); else if (r != SNSR_RC_OK) fatalSession(s); /* Partial results might not be available, ignore handler setup errors. */ partial.verbose = verbose; r = snsrSetHandler(s, SNSR_PARTIAL_RESULT_EVENT, snsrCallback(resultEvent, NULL, &partial)); if (r == SNSR_RC_SETTING_NOT_FOUND) snsrClearRC(s); /* VAD callback handlers. These are not supported for all task types. */ vadContext.verbose = verbose; if (dir) { size_t dirLen = strlen(dir); vadContext.length = dirLen + 32; vadContext.filename = malloc(vadContext.length); if (!vadContext.filename) fatal(s, SNSR_RC_NO_MEMORY, "Could not allocate output filename buffer"); strcpy(vadContext.filename, dir); if (!dirLen) strcat(vadContext.filename, "./"); else if (dir[dirLen - 1] != '/') strcat(vadContext.filename, "/"); vadContext.prefix = strlen(vadContext.filename); } snsrSetHandler(s, SNSR_BEGIN_EVENT, snsrCallback(vadBeginEvent, NULL, &vadContext)); snsrSetHandler(s, SNSR_SILENCE_EVENT, snsrCallback(vadSilenceEvent, NULL, &vadContext)); snsrSetHandler(s, SNSR_END_EVENT, snsrCallback(vadEndEvent, NULL, &vadContext)); snsrSetHandler(s, SNSR_LIMIT_EVENT, snsrCallback(vadEndEvent, NULL, &vadContext)); /* Ignore not-found errors for VAD handlers */ if (snsrRC(s) == SNSR_RC_SETTING_NOT_FOUND) snsrClearRC(s); /* Prefer NLU intent events added in TrulyNatural 7.1.0 */ if (verbose > -3) { r = snsrSetHandler(s, SNSR_NLU_INTENT_EVENT, snsrCallback(intentEvent, NULL, NULL)); if (r == SNSR_RC_SETTING_NOT_FOUND || verbose > 1) { snsrClearRC(s); /* NLU slot events were added in TrulyNatural 6.13.0. */ r = snsrSetHandler(s, SNSR_NLU_SLOT_EVENT, snsrCallback(nluEvent, NULL, NULL)); if (r == SNSR_RC_SETTING_NOT_FOUND) snsrClearRC(s); } } /* Events introdcued by model version 0.13.0. */ if (verbose > 1) { snsrSetHandler(s, SNSR_LISTEN_BEGIN_EVENT, snsrCallback(showEvent, NULL, NULL)); snsrSetHandler(s, SNSR_LISTEN_END_EVENT, snsrCallback(showEvent, NULL, NULL)); /* Treat these as optional, for compatibility with older spotter models. */ if (snsrRC(s) == SNSR_RC_SETTING_NOT_FOUND) snsrClearRC(s); } /* Continuous Adaptation spotters provide additional events. */ if (verbose > 0) { snsrSetHandler(s, SNSR_ADAPT_STARTED_EVENT, snsrCallback(adaptStartedEvent, NULL, NULL)); snsrSetHandler(s, SNSR_ADAPTED_EVENT, snsrCallback(showEvent, NULL, NULL)); snsrSetHandler(s, SNSR_NEW_USER_EVENT, snsrCallback(showEvent, NULL, (void *)1)); /* Treat these as optional as only CA spotters support them */ if (snsrRC(s) == SNSR_RC_SETTING_NOT_FOUND) snsrClearRC(s); } /* SLM events are optional */ if (verbose > -3) { snsrSetHandler(s, SNSR_SLM_START_EVENT, snsrCallback(slmStartEvent, NULL, NULL)); snsrSetHandler(s, SNSR_SLM_PARTIAL_RESULT_EVENT, snsrCallback(slmPartialResultEvent, NULL, NULL)); snsrSetHandler(s, SNSR_SLM_RESULT_EVENT, snsrCallback(slmResultEvent, NULL, NULL)); if (snsrRC(s) == SNSR_RC_SETTING_NOT_FOUND) snsrClearRC(s); } r = snsrRun(s); if (r != SNSR_RC_OK && r != SNSR_RC_STREAM_END) fatalSession(s); free(vadContext.filename); if (profile == 1) { showRealTimeFactor(s, NULL); showRealTimeFactor(s, SNSR_SLOT_0); showRealTimeFactor(s, SNSR_SLOT_1); showRealTimeFactor(s, "0.0."); showRealTimeFactor(s, "2.0."); } else if (profile > 1) { snsrProfile(s, snsrStreamFromFILE(stdout, SNSR_ST_MODE_WRITE)); } if (save) { snsrReset(s); snsrSave(s, SNSR_FM_CONFIG, snsrStreamFromFileName(save, "w")); quitOnError(s); if (verbose > 0) printf("Model saved to \"%s\".\n", save); } snsrRelease(s); snsrTearDown(); if (out && verbose > 0) printf("VAD audio saved to \"%s\".\n", out); return 0; } ``` *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/c/spot-convert.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/spot-convert/" --- # spot-convert.c This is the source code for the [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) command-line tool. ## Instructions See [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert). ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/spot-convert.c_ **spot-convert.c:** ```c /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK model conversion command-line utility. *------------------------------------------------------------------------------ */ #include #include #include #include #include #define EMBED_TASK_VERSION "~0.6.0 || 1.0.0" #define HEADER_NAME "-search.h" #define SEARCH_NAME "-search.bin" #define ACMODEL_NAME "-net.bin" #define FILENAME_SIZE 1023 #define KEY_SIZE 64 #define TARGET_SIZE 16 #if defined(_MSC_VER) && (_MSC_VER < 1900) # define snprintf _snprintf #endif typedef struct { const char *basename; /* output file prefix */ const char *slot; /* slot prefix */ const char *target; /* embedded target descriptor */ int fileNameInfo; /* append version and operating point to filename */ int outputC; /* true to generate C output files */ int point; /* operating point to convert */ int verbose; /* feedback verbosity */ } ConvertContext; static void fatal(int rc, const char *format, ...) { va_list a; fprintf(stderr, "ERROR: "); va_start(a, format); vfprintf(stderr, format, a); va_end(a); fprintf(stderr, "\n"); exit(rc); } /* Concatenates head, ".", and tail into key, and returns * a pointer to key. */ const char * slotKey(const char *head, const char *tail, char key[KEY_SIZE + 1]) { if (strlen(head) + strlen(tail) + 2 > KEY_SIZE) fatal(SNSR_RC_INVALID_ARG, "-q slotname prefix is too long."); strncpy(key, head, KEY_SIZE); strncat(key, ".", KEY_SIZE); strncat(key, tail, KEY_SIZE); key[KEY_SIZE - 1] = '\0'; return key + (*head == '\0'); /* skip leading . if head is empty */ } static void writeFile(SnsrStream model, ConvertContext *ctx, const char *tag, const char *pre, const char *ver, const char *prod, const char *mid, const char *post, const char *ext, const char *mode) { SnsrRC r; SnsrStream output; size_t written; char filename[FILENAME_SIZE + 1]; filename[FILENAME_SIZE] = '\0'; strncpy(filename, pre, FILENAME_SIZE); if (ctx->fileNameInfo) { if (ver) { strncat(filename, ver, FILENAME_SIZE); strncat(filename, "-", FILENAME_SIZE); } strncat(filename, mid, FILENAME_SIZE); strncat(filename, prod, FILENAME_SIZE); } strncat(filename, post, FILENAME_SIZE); strncat(filename, ext, FILENAME_SIZE); written = snsrStreamGetMeta(model, SNSR_ST_META_BYTES_WRITTEN); output = snsrStreamFromFileName(filename, mode); snsrRetain(output); snsrStreamCopy(output, model, written); r = snsrStreamRC(output); if (r != SNSR_RC_OK) fatal(r, snsrStreamErrorDetail(output)); snsrRelease(output); if (ctx->verbose > 0) { printf("wrote %s to \"%s\"\n", tag, filename); fflush(stdout); } } static SnsrRC writeEmbeddedFiles(SnsrSession s, ConvertContext *ctx, const char *slot) { SnsrRC r; SnsrStream net = NULL, sch = NULL, hdr = NULL; #define OP_SIZE 6 char op[OP_SIZE]; char kb[KEY_SIZE + 1]; char srcTarget[TARGET_SIZE + 1]; const char *tSliceVersion = NULL; int prodReady = 0; const char *key, *prod = "prod-"; r = snsrSetString(s, slotKey(slot, SNSR_EMBEDDED_TARGET, kb), ctx->target); if (r == SNSR_RC_SETTING_NOT_FOUND) fatal(snsrRC(s), "This model cannot be converted to DSP format." " (%s)", snsrErrorDetail(s)); snsrGetStream(s, slotKey(slot, SNSR_EMBEDDED_ACMODEL_STREAM, kb), &net); if (net) snsrRetain(net); snsrGetStream(s, slotKey(slot, SNSR_EMBEDDED_SEARCH_STREAM, kb), &sch); if (sch) snsrRetain(sch); snsrGetStream(s, slotKey(slot, SNSR_EMBEDDED_HEADER_STREAM, kb), &hdr); if (hdr) snsrRetain(hdr); key = slotKey(slot, SNSR_RES_MIN_EMBEDDED_VERSION, kb); snsrGetString(s, key, &tSliceVersion); if (tSliceVersion) snsrRetain(tSliceVersion); key = slotKey(slot, SNSR_RES_EMBEDDED_MODEL_PRODUCTION_READY, kb); r = snsrGetInt(s, key, &prodReady); if (r != SNSR_RC_OK) fatal(snsrRC(s), "%s", snsrErrorDetail(s)); snprintf(op, OP_SIZE, "op%02i-", ctx->point); if (ctx->verbose > 0) { printf("operating-point: %i\n", ctx->point); fflush(stdout); } if (!prodReady) prod = "dev-"; if (ctx->verbose > 0) { printf("production-ready: %s\n", prodReady? "yes": "no"); fflush(stdout); } writeFile(net, ctx, "acoustic model (bin)", ctx->basename, tSliceVersion, prod, op, "net", ".bin", "w"); snsrRelease(net); writeFile(sch, ctx, "search model (bin)", ctx->basename, tSliceVersion, prod, op, "search", ".bin", "w"); snsrRelease(sch); writeFile(hdr, ctx, "search header", ctx->basename, tSliceVersion, prod, op, "search", ".h", "wt"); snsrRelease(hdr); if (ctx->outputC) { memset(srcTarget, 0, TARGET_SIZE + 1); strncpy(srcTarget, "src:", TARGET_SIZE); strncat(srcTarget, ctx->target, TARGET_SIZE); snsrSetString(s, slotKey(slot, SNSR_EMBEDDED_TARGET, kb), srcTarget); snsrGetStream(s, slotKey(slot, SNSR_EMBEDDED_ACMODEL_STREAM, kb), &net); writeFile(net, ctx, "acoustic model (C)", ctx->basename, tSliceVersion, prod, op, "net", ".c", "wt"); snsrGetStream(s, slotKey(slot, SNSR_EMBEDDED_SEARCH_STREAM, kb), &sch); writeFile(sch, ctx, "search model (C)", ctx->basename, tSliceVersion, prod, op, "search", ".c", "wt"); } snsrRelease(tSliceVersion); return snsrRC(s); } static SnsrRC convertAllPoints(SnsrSession s, const char *key, void *data) { ConvertContext *c = (ConvertContext *)data; const char *slot = c->slot; char keyBuff[KEY_SIZE + 1]; SnsrRC r; snsrGetInt(s, slotKey(slot, SNSR_RES_AVAILABLE_POINT, keyBuff), &c->point); r = snsrSetInt(s, slotKey(slot, SNSR_OPERATING_POINT, keyBuff), c->point); if (r != SNSR_RC_OK) return r; return writeEmbeddedFiles(s, c, slot); } static const char *usageDetail = "Output filenames are determined by the model parameters:\n" " $(prefix) [-] [slot$(slotname)-] $(target)- $(version)-\n" " op$(operating-point)- {dev,prod}- {net,search}.{bin,c,h}\n" "where:\n" " prefix specified by the -p option, or taken from the filename\n" " of the task if -p isn't used.\n" " version is the oldest DSP library that can run this model.\n" " -dev- models are limited in runtime or number of recognition\n" " events and should not be used in products.\n" " -prod- models are not limited and ready for production use.\n" "\n" "Use the -o option to override this filename pattern to:\n" " $(prefix)[-]{net,search}.{bin,c,h}\n" "\n" "The -o and -a options are mutually exclusive.\n" "\n" "Output filenames are constrained to never start with \"-\"\n" "\n" "Settings are strings used as keys to query or change task behavior.\n" "Most frequently used for wake words and command sets is operating-point.\n" "Refer to the " SNSR_NAME " SDK documentation for a complete list and\n" "descriptions of all supported settings.\n"; static void usage(const char *name) { SnsrSession s; const char *libInfo; fprintf(stderr, "Converts " SNSR_NAME " SDK wake word models to " "THF Micro format.\n\n"); fprintf(stderr, "usage: %s -t task [options] target\n" " options:\n" " -a : convert all operating-points\n" " -c : create .c output (in addition to .bin)\n" " -o output : full prefix for output filenames\n" " -p output-prefix : prefix for output filenames " "(default: task-target-)\n" " -q slotname : model slot prefix\n" " -s setting=value : override a task setting\n" " -t task : set a task filename (required)\n" " -v [-v [-v]] : increase verbosity\n", name); fprintf(stderr, "\n%s", usageDetail); snsrNew(&s); snsrGetString(s, SNSR_LIBRARY_INFO, &libInfo); fprintf(stderr, "\n%s\n", libInfo); snsrRelease(s); exit(199); } /* Report model license keys that have imminent expiration dates. */ static void reportExpiringModelLicense(SnsrSession s, const char *modelfile) { const char *expWarning = NULL; snsrGetString(s, SNSR_MODEL_LICENSE_WARNING, &expWarning); if (expWarning) fprintf(stderr, "WARNING for model \"%s\": %s.\n", modelfile, expWarning); } int main(int argc, char *argv[]) { SnsrRC r; SnsrSession s; char basename[FILENAME_SIZE + 1]; char keyBuff[KEY_SIZE + 1]; int allPoints = 0, o; const char *prefix = NULL, *task = NULL; ConvertContext ctx; extern char *optarg; extern int optind; #ifdef SNSR_USE_SECURITY_CHIP uint32_t *securityChipComms(uint32_t *in); snsrConfig(SNSR_CONFIG_SECURITY_CHIP, securityChipComms); #endif if (argc == 1) usage(argv[0]); ctx.basename = basename; ctx.slot = ""; ctx.target = NULL; ctx.outputC = 0; ctx.point = 0; ctx.fileNameInfo = 1; ctx.verbose = 0; r = snsrNew(&s); if (r != SNSR_RC_OK) fatal(r, s? snsrErrorDetail(s): snsrRCMessage(r)); while ((o = getopt(argc, argv, "aco:p:q:s:t:v?")) >= 0) { switch (o) { case 'a': allPoints = 1; break; case 'c': ctx.outputC = 1; break; case 'o': prefix = optarg; ctx.fileNameInfo = 0; break; case 'p': prefix = optarg; break; case 'q': ctx.slot = optarg; break; case 's': r = snsrSet(s, optarg); if (r == SNSR_RC_NO_MODEL) fatal(r, "Set -t task before -s setting=value"); else if (r != SNSR_RC_OK) fatal(r, snsrErrorDetail(s)); break; case 't': snsrLoad(s, snsrStreamFromFileName(optarg, "r")); snsrRequire(s, SNSR_TASK_TYPE, SNSR_PHRASESPOT); r = snsrRequire(s, SNSR_TASK_VERSION, EMBED_TASK_VERSION); if (r != SNSR_RC_OK) fatal(r, snsrErrorDetail(s)); task = optarg; reportExpiringModelLicense(s, optarg); break; case 'v': ctx.verbose++; break; case '?': default: usage(argv[0]); } } if (optind != argc - 1) usage(argv[0]); ctx.target = argv[optind]; if (allPoints && !ctx.fileNameInfo) fatal(SNSR_RC_INVALID_ARG, "The -a and -o options are mutually exclusive."); r = snsrRequire(s, SNSR_TASK_TYPE, SNSR_PHRASESPOT); if (r == SNSR_RC_NO_MODEL) usage(argv[0]); /* We'll include the source filename in the header output */ r = snsrSetString(s, SNSR_MODEL_NAME, task); if (r != SNSR_RC_OK) fatal(r, snsrErrorDetail(s)); /* Output filename prefix buffer */ basename[FILENAME_SIZE] = '\0'; if (prefix) strncpy(basename, prefix, FILENAME_SIZE); else { char *e; assert(task); if ((e = (char *)strrchr(task, '/'))) strncpy(basename, e + 1, FILENAME_SIZE); else strncpy(basename, task, FILENAME_SIZE); if ((e = strrchr(basename, '.'))) *e = '\0'; } if (*basename) strncat(basename, "-", FILENAME_SIZE); if (ctx.fileNameInfo) { char *e; size_t len; if (*ctx.slot) { len = strlen(basename); snprintf(basename + len, FILENAME_SIZE - len, "slot%s-", ctx.slot); } len = strlen(basename); snprintf(basename + len, FILENAME_SIZE - len, "%s-", ctx.target); if ((e = strchr(basename + len, ':'))) *e = '_'; } if (ctx.verbose > 1) { printf("target: %s\n", ctx.target); printf("basename: %s\n", ctx.basename); fflush(stdout); } if (allPoints) { snsrForEach(s, slotKey(ctx.slot, SNSR_OPERATING_POINT_LIST, keyBuff), snsrCallback(convertAllPoints, NULL, &ctx)); } else { /* Very old models do not have support for operating points */ if (snsrRC(s) != SNSR_RC_OK) fatal(snsrRC(s), snsrErrorDetail(s)); snsrGetInt(s, slotKey(ctx.slot, SNSR_OPERATING_POINT, keyBuff), &ctx.point); snsrClearRC(s); writeEmbeddedFiles(s, &ctx, ctx.slot); } if (snsrRC(s) != SNSR_RC_OK) fatal(snsrRC(s), snsrErrorDetail(s)); snsrRelease(s); snsrTearDown(); return 0; } ``` *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/c/spot-data-stream.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data-stream/" --- # spot-data-stream.c This example runs a wake word from code space with a [custom audio stream](https://doc.sensory.com/tnl/7.8/api/sample/c/data-stream.md#data-streamc), using pull mode processing with [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run). It is a reasonable starting point for running on a small device with an RTOS. **Also see these related items:** [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider), [data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/data-stream.md#data-streamc) ## Instructions [Build](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#examples-cmake) the sample code. In the same terminal window type the command after the `%`: ```console % ./bin/spot-data-stream Spotted "hello blue genie" from sample 6720 to sample 18000 Done, found phrase. ``` ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/spot-data-stream.c_ **spot-data-stream.c:** ```c /* Sensory Confidential * Copyright (C)2018-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK example illustrating the use of the * sample custom data-stream (see data-stream.c) This should * be easily adaptable to a custom live-audio stream * (in case of a custom audio driver for RTOS for example.) * * The spotter model is loaded from code space. On platforms where code is * read directly from ROM, this will reduce heap requirements. *----------------------------------------------------------------------------- */ #include #include #include #include "data-stream.h" /* See spot-hbg-enUS-1.4.0-m.c */ extern SnsrCodeModel spot_hbg_enUS; /* NOTE: extern char * foo is NOT always the same as extern char foo[] */ extern unsigned char audioData[]; extern unsigned int audioDataLen; /* Result callback function, see snsrSetHandler() below. * Print the result text and the start and end sample indices of * the first spotted phrase. */ static SnsrRC resultEvent(SnsrSession s, const char *key, void *privateData) { SnsrRC rc; const char *phrase; double begin, end; /* Retrieve the phrase text and alignments from the session handle */ snsrGetDouble(s, SNSR_RES_BEGIN_SAMPLE, &begin); snsrGetDouble(s, SNSR_RES_END_SAMPLE, &end); rc = snsrGetString(s, SNSR_RES_TEXT, &phrase); /* Quit early if an error occurred. */ if (rc != SNSR_RC_OK) return rc; printf("\nSpotted \"%s\" from sample %d to sample %d\n", phrase, (int)begin, (int)end); /* This return code from the event handler sets the * return code in the SnsrSession and causes the session * to stop */ return SNSR_RC_STOP; } int main(int argc, char **argv) { SnsrRC rc; SnsrSession s = NULL; SnsrStream audioStream = NULL; rc = snsrNew(&s); if (rc != SNSR_RC_OK) { const char *err = s ? snsrErrorDetail(s) : snsrRCMessage(rc); fprintf(stderr, "Error on init: %d - %s\n", rc, err); return rc; } /* Load and validate the spotter model task from code space */ snsrLoad(s, snsrStreamFromCode(spot_hbg_enUS)); if (snsrRequire(s, SNSR_TASK_TYPE, SNSR_PHRASESPOT) != SNSR_RC_OK) { fprintf(stderr, "Error loading spotter: %s\n", snsrErrorDetail(s)); return rc; } /* Register a result callback. Private data handle is not used. */ snsrSetHandler(s, SNSR_RESULT_EVENT, snsrCallback(resultEvent, NULL, NULL)); /* NOTE: Audio stream should be 16 KHz, 16 bits/sample, mono */ /* NOTE: Directly casting char to short works on little-endian only */ /* ARM and x86 are little-endian, MIPS may not be */ audioStream = streamFromData(audioData, audioDataLen, SNSR_ST_MODE_READ); snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM, audioStream); /* snsrRun won't return until stopped or interrupted or end of data */ rc = snsrRun(s); switch (rc) { case SNSR_RC_OK: printf("Done, no error but no phrase.\n"); break; case SNSR_RC_STOP: printf("Done, found phrase.\n"); break; case SNSR_RC_STREAM_END: printf("Reached end of stream.\n"); break; default: printf("Unexpected return: %d\n", rc); return rc; } printf("\n"); if (s) snsrRelease(s); /* audioStream has already been released because session had * the only reference to it - so don't snsrRelease it again. */ return 0; } ``` *[API]: Application Programming Interface *[RTOS]: Real-Time Operating System *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/c/spot-data.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data/" --- # spot-data.c This example runs a small keyword spotter from code space. It uses a [custom memory allocator](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloctlsf) to avoid calls to the system heap allocator, and reads audio data from code space to avoid file system use. Uses [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) for audio processing. This is a good starting point for applications running on small embedded devices without full operating system support. ## Instructions [Build](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#examples-cmake) the sample code. In the same terminal window type the command after the `%`: ```console % ./bin/spot-data Spotted "hello blue genie" from sample 6720 to sample 18000 Phrase spotted. ``` ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/spot-data.c_ **spot-data.c:** ```c /* Sensory Confidential * Copyright (C)2018-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK example illustrating the simplest way * to get data from whatever source (custom RTOS audio driver perhaps) * and push the data into the input stream and get results from the session. * * Illustrates the use of a custom memory allocator to avoid runtime * allocations from the system heap, and use of a panic function to * recover from otherwise fatal memory errors. * * Similar to sample push-audio.c but even simpler and does not use * a filesystem. * * The spotter model is loaded from code space. On platforms where code is * read directly from ROM, this will reduce heap requirements. *----------------------------------------------------------------------------- */ #include #include #include #include #include /* See spot-hbg-enUS-1.4.0-m.c */ extern SnsrCodeModel spot_hbg_enUS; /* See data.c */ extern unsigned char audioData[]; extern unsigned int audioDataLen; /* Process one 15 ms audio block at a time. * Most spotters run at a 15 ms frame rate. Matching the processing block * size to the frame rate reduces live audio processing overhead to a minimum. * Larger blocks will result in fewer calls to snsrPush(), but add latency. * Smaller blocks are accumulated in snsrPush() until at least a frame's worth * is available. */ #define BLOCK_MS 15 #define SAMPLE_RATE 16000 #define BLOCK_BYTES (BLOCK_MS * SAMPLE_RATE / 1000 * sizeof(short)) /* Heap backing store, see snsrConfig(SNSR_CONFIG_ALLOC, ...) call in main. * * Set HEAP_SIZE to 100000 to trigger an out-of-memory panic and and * subsequent recovery. */ #define HEAP_SIZE 200000 static size_t HeapPool[HEAP_SIZE / sizeof(size_t)]; /* Utility, returns the lesser of a and b */ #define MIN(a, b) ((a) < (b)? (a): (b)) /* Result callback function, see snsrSetHandler() below. * Print the result text and the start and end sample indices of * the first spotted phrase. */ static SnsrRC resultEvent(SnsrSession s, const char *key, void *privateData) { SnsrRC rc; const char *phrase; double begin, end; /* Retrieve the phrase text and alignments from the session handle */ snsrGetDouble(s, SNSR_RES_BEGIN_SAMPLE, &begin); snsrGetDouble(s, SNSR_RES_END_SAMPLE, &end); rc = snsrGetString(s, SNSR_RES_TEXT, &phrase); /* Quit early if an error occurred. */ if (rc != SNSR_RC_OK) return rc; printf("\nSpotted \"%s\" from sample %d to sample %d\n", phrase, (int)begin, (int)end); /* This return code from the event handler sets the * return code in the SnsrSession. */ return SNSR_RC_STOP; } /* Saved calling environment used by panicFunc() below */ static jmp_buf PanicJmp; /* This function handles unrecoverable errors. Here it logs a message * to the console, then does a longjmp to the very start of the application * where a recovery attempt is made. */ static void panicFunc(const char *format, va_list a) { fprintf(stderr, "\nPANIC: "); vfprintf(stderr, format, a); fprintf(stderr, "\n\n"); longjmp(PanicJmp, SNSR_RC_NO_MEMORY); } int main(int argc, char **argv) { SnsrRC rc; SnsrSession s = NULL; int jmp; unsigned i; /* Register a custom panic handler */ snsrConfig(SNSR_CONFIG_PANIC_FUNC, panicFunc); if ((jmp = setjmp(PanicJmp))) { /* Out-of-memory error occurred. Abandon heap, re-initialize */ snsrTearDown(); fprintf(stderr, "Restarting application with default allocator.\n"); } else { /* Use a custom allocator to avoid calls to malloc(), et al */ rc = snsrConfig(SNSR_CONFIG_ALLOC, snsrAllocTLSF(HeapPool, sizeof(HeapPool))); if (rc != SNSR_RC_OK) { fprintf(stderr, "Custom allocation failure: %s\n", snsrRCMessage(rc)); return rc; } } rc = snsrNew(&s); if (rc != SNSR_RC_OK) { fprintf(stderr, "ERROR: %s\n", s? snsrErrorDetail(s) : snsrRCMessage(rc)); return rc; } /* Load and validate the spotter model task from code space */ snsrLoad(s, snsrStreamFromCode(spot_hbg_enUS)); if (snsrRequire(s, SNSR_TASK_TYPE, SNSR_PHRASESPOT) != SNSR_RC_OK) { fprintf(stderr, "ERROR: %s\n", snsrErrorDetail(s)); return rc; } /* Register a result callback. Private data handle is not used. */ snsrSetHandler(s, SNSR_RESULT_EVENT, snsrCallback(resultEvent, NULL, NULL)); /* Main loop. Push all audio data through the recognizer pipeline. */ for (i = 0; i < audioDataLen; i += BLOCK_BYTES) { rc = snsrPush(s, SNSR_SOURCE_AUDIO_PCM, audioData + i, MIN(BLOCK_BYTES, audioDataLen - i)); if (rc == SNSR_RC_STOP) { printf("Phrase spotted.\n"); fflush(stdout); snsrClearRC(s); } else if (rc != SNSR_RC_OK) { fprintf(stderr, "ERROR: %s\n", snsrErrorDetail(s)); return rc; } } /* Flush any remaining internally-buffered audio */ rc = snsrStop(s); snsrRelease(s); snsrTearDown(); return rc; } ``` *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/c/spot-enroll.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/spot-enroll/" --- # spot-enroll.c This is the source code for the [spot-enroll](https://doc.sensory.com/tnl/7.8/tools/spot-enroll.md#spot-enroll) command-line tool. ## Instructions See [spot-enroll](https://doc.sensory.com/tnl/7.8/tools/spot-enroll.md#spot-enroll). ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/spot-enroll.c_ **spot-enroll.c:** ```c /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK keyword spotting command-line enrollment utility. *------------------------------------------------------------------------------ */ #include #include #include #include #define DEFAULT_OUT "enrolled-sv.snsr" #define ENROLL_TASK_VERSION "~0.10.0 || 1.0.0" typedef struct { const char *enrollfile; /* current enrollment filename */ const char **filename; /* enrollment filenames, for error messages */ const char *enrolled; /* optional enrollment context file name */ const char *adapted; /* optional adapted context file name */ const char *model; /* enrolled phrase spotter output file name */ size_t fileCount; /* number of allocated filenames */ int failed; /* number of failed enrollments */ int verbosity; /* incremented by the -v flag */ } EnrollContext; static SnsrRC doneEvent(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; SnsrRC r; SnsrStream model = NULL, out; size_t written; r = snsrGetStream(s, SNSR_MODEL_STREAM, &model); if (r != SNSR_RC_OK) return r; written = snsrStreamGetMeta(model, SNSR_ST_META_BYTES_WRITTEN); out = snsrStreamFromFileName(e->model, "w"); snsrStreamCopy(out, model, written); r = snsrStreamRC(out); if (r != SNSR_RC_OK) snsrDescribeError(s, "%s", snsrStreamErrorDetail(out)); snsrRelease(out); if (r == SNSR_RC_OK && e->verbosity >= 1) { printf("Enrolled model saved to \"%s\"\n", e->model); fflush(stdout); } return r; } static SnsrRC adaptedEvent(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; SnsrRC r; r = snsrSave(s, SNSR_FM_RUNTIME, snsrStreamFromFileName(e->adapted, "w")); if (r == SNSR_RC_OK && e->verbosity >= 1) { printf("Adapted enrollment context saved to \"%s\"\n", e->adapted); fflush(stdout); } return r; } static SnsrRC enrolledEvent(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; SnsrRC r; r = snsrSave(s, SNSR_FM_RUNTIME, snsrStreamFromFileName(e->enrolled, "w")); if (r == SNSR_RC_OK && e->verbosity >= 1) { printf("Enrollment context saved to \"%s\"\n", e->enrolled); fflush(stdout); } return r; } static SnsrRC printReason(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; const char *guidance, *reason; int pass = 0; double value = 0.0, threshold = 0.0; snsrGetInt(s, SNSR_RES_REASON_PASS, &pass); if (pass) return snsrRC(s); snsrGetString(s, SNSR_RES_REASON, &reason); snsrGetString(s, SNSR_RES_GUIDANCE, &guidance); snsrGetDouble(s, SNSR_RES_REASON_VALUE, &value); snsrGetDouble(s, SNSR_RES_REASON_THRESHOLD, &threshold); if (snsrRC(s) == SNSR_RC_OK) { fprintf(stderr, " reason: %s", reason); if (e->verbosity >= 2) fprintf(stderr, " (%.2f, threshold is %.2f)", value, threshold); fprintf(stderr, "\n fix: %s\n", guidance); fflush(stdout); } return snsrRC(s); } static SnsrRC failEvent(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; SnsrRC r; int id; r = snsrGetInt(s, SNSR_RES_ENROLLMENT_ID, &id); if (r != SNSR_RC_OK) return r; fprintf(stderr, "Enrollment from file \"%s\" failed:\n", (size_t)id < e->fileCount? e->filename[id]: e->enrollfile); printReason(s, key, privateData); if (e->verbosity >= 3) { fprintf(stderr, "\nAll failed checks:\n"); snsrForEach(s, SNSR_REASON_LIST, snsrCallback(printReason, NULL, e)); } fflush(stdout); e->failed++; return SNSR_RC_OK; } static SnsrRC passEvent(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; SnsrRC r; int id; r = snsrGetInt(s, SNSR_RES_ENROLLMENT_ID, &id); if (r != SNSR_RC_OK) return r; if ((size_t)id >= e->fileCount) { e->fileCount++; e->filename = (const char **)realloc((char **)e->filename, sizeof(*e->filename) * e->fileCount); } e->filename[id] = e->enrollfile; return SNSR_RC_OK; } static SnsrRC progEvent(SnsrSession s, const char *key, void *privateData) { SnsrRC r = SNSR_RC_OK; EnrollContext *e = (EnrollContext *)privateData; if (e->verbosity >= 1) { double progress; r = snsrGetDouble(s, SNSR_RES_PERCENT_DONE, &progress); if (r == SNSR_RC_OK) { printf("\rAdapting: %3.0f%% complete.", progress); if (progress >= 100) printf("\n"); fflush(stdout); } } return r; } static SnsrRC userIterator(SnsrSession s, const char *key, void *privateData) { EnrollContext *e = (EnrollContext *)privateData; SnsrRC r; int count, recommended; const char *user; snsrGetString(s, SNSR_USER, &user); snsrGetInt(s, SNSR_ENROLLMENT_TARGET, &recommended); r = snsrGetInt(s, SNSR_RES_ENROLLMENT_COUNT, &count); if (r == SNSR_RC_OK) { if (e->verbosity >= 2) printf("%16s: %u enrollment%s.\n", user, count, count == 1? "": "s"); if (count != recommended) fprintf(stderr, "WARNING: \"%s\" has %i enrollment%s, task recommends " "%i for optimal performance.\n", user, count, count == 1? "": "s", recommended); fflush(stdout); } return r; } static void fatal(int rc, const char *format, ...) { va_list a; fprintf(stderr, "ERROR: "); va_start(a, format); vfprintf(stderr, format, a); va_end(a); fprintf(stderr, "\n"); exit(rc); } static const char *usageDetail = "Settings are strings used as keys to query or change task behavior.\n" "Most frequently used for enrollment is accuracy, which takes a value\n" "between 0 and 1.\n" "Refer to the " SNSR_NAME " SDK documentation for a complete list and\n" "descriptions of all supported settings.\n"; static void usage(const char *name) { SnsrSession s; const char *libInfo; fprintf(stderr, "Enrolls " SNSR_NAME " SDK wake words on audio files.\n\n"); fprintf(stderr, "usage: %s -t task [options] " "[+user1 file1 [-c] file2 ...] [+user2 ...]\n" " options:\n" " -a adaptedfile : adapted enrollment context output filename\n" " -c file : recording contains trailing context\n" " -e enrolledfile : enrollment context output filename\n" " -o out : enrolled model output filename (default: " DEFAULT_OUT ")\n" " -s setting=value : override a task setting\n" " -t task : specify task filename (required)\n" " -v [-v [-v]] : increase verbosity\n", name); fprintf(stderr, "\n%s", usageDetail); snsrNew(&s); snsrGetString(s, SNSR_LIBRARY_INFO, &libInfo); fprintf(stderr, "\n%s\n", libInfo); snsrRelease(s); exit(199); } /* Report model license keys. */ static void reportModelLicense(SnsrSession s, const char *modelfile, int verbose) { const char *msg = NULL; if (verbose > 1) { snsrGetString(s, SNSR_MODEL_LICENSE_EXPIRES, &msg); if (msg) fprintf(stderr, "\"%s\": %s.\n", modelfile, msg); } msg = NULL; snsrGetString(s, SNSR_MODEL_LICENSE_WARNING, &msg); if (msg) fprintf(stderr, "WARNING for model \"%s\": %s.\n", modelfile, msg); } /* List enrollment phrases and IDs, where available */ static SnsrRC showVocab(SnsrSession s, const char *key, void *privateData) { SnsrRC r; const char *text = NULL; int id = -1, *first = (int *)privateData; snsrGetInt(s, SNSR_RES_ID, &id); r = snsrGetString(s, SNSR_RES_TEXT, &text); if (r != SNSR_RC_OK) return r; if (*first) printf("Available vocabulary:\n"); printf(" %2i: \"%s\"\n", id, text); *first = 0; return r; } int main(int argc, char *argv[]) { EnrollContext e; SnsrRC r; SnsrSession s; int i, o, rejected = 0; const char *msg = NULL; extern char *optarg; extern int optind; const char *u = NULL; #ifdef SNSR_USE_SECURITY_CHIP uint32_t *securityChipComms(uint32_t *in); snsrConfig(SNSR_CONFIG_SECURITY_CHIP, securityChipComms); #endif if (argc == 1) usage(argv[0]); r = snsrNew(&s); if (r != SNSR_RC_OK) fatal(r, s? snsrErrorDetail(s): snsrRCMessage(r)); e.failed = 0; e.verbosity = 0; e.enrolled = NULL; e.adapted = NULL; e.model = DEFAULT_OUT; e.fileCount = 0; e.filename = NULL; while ((o = getopt(argc, argv, "+a:e:o:s:t:v?")) >= 0) { switch (o) { case 'a': e.adapted = optarg; break; case 'e': e.enrolled = optarg; break; case 'o': e.model = optarg; break; case 's': r = snsrSet(s, optarg); if (r == SNSR_RC_NO_MODEL) fatal(r, "set -t task before -s setting=value"); else if (r != SNSR_RC_OK) fatal(r, snsrErrorDetail(s)); break; case 't': snsrLoad(s, snsrStreamFromFileName(optarg, "r")); snsrRequire(s, SNSR_TASK_TYPE, SNSR_ENROLL); r = snsrRequire(s, SNSR_TASK_VERSION, ENROLL_TASK_VERSION); if (r != SNSR_RC_OK) fatal(r, snsrErrorDetail(s)); reportModelLicense(s, optarg, e.verbosity); break; case 'v': e.verbosity++; break; case '?': default: usage(argv[0]); } } r = snsrSetInt(s, SNSR_INTERACTIVE_MODE, 0); if (r == SNSR_RC_NO_MODEL) usage(argv[0]); /* Report application license status */ if (e.verbosity > 1) { snsrGetString(s, SNSR_LICENSE_EXPIRES, &msg); if (msg) fprintf(stderr, "\"%s\": %s.\n", argv[0], msg); } msg = NULL; snsrGetString(s, SNSR_LICENSE_WARNING, &msg); if (msg) fprintf(stderr, "WARNING for \"%s\": %s.\n", argv[0], msg); snsrSetHandler(s, SNSR_DONE_EVENT, snsrCallback(doneEvent, NULL, &e)); snsrSetHandler(s, SNSR_FAIL_EVENT, snsrCallback(failEvent, NULL, &e)); snsrSetHandler(s, SNSR_PASS_EVENT, snsrCallback(passEvent, NULL, &e)); snsrSetHandler(s, SNSR_PROG_EVENT, snsrCallback(progEvent, NULL, &e)); if (e.enrolled) snsrSetHandler(s, SNSR_ENROLLED_EVENT, snsrCallback(enrolledEvent, NULL, &e)); if (e.adapted) snsrSetHandler(s, SNSR_ADAPTED_EVENT, snsrCallback(adaptedEvent, NULL, &e)); /* SNSR_VOCAB_LIST is supported for a subset of models only, ignore errors */ if (e.verbosity > 2 && snsrRC(s) == SNSR_RC_OK) { int first = 1; snsrForEach(s, SNSR_VOCAB_LIST, snsrCallback(showVocab, NULL, &first)); snsrClearRC(s); } if (optind + 1 < argc) { int enrollmentIndex = 0, idx = -1, errors; if (argv[optind][0] != '+') usage(argv[0]); for (i = optind; i < argc; i++) { if (argv[i][0] == '+') { u = argv[i] + 1; snsrSetString(s, SNSR_USER, u); } else { SnsrStream a; int hasContext; hasContext = !strcmp("-c", argv[i]); if (hasContext && ++i >= argc) usage(argv[0]); a = snsrStreamFromFileName(argv[i], "r"); e.enrollfile = argv[i]; a = snsrStreamFromAudioStream(a, SNSR_ST_AF_DEFAULT); snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM, a); snsrSetInt(s, SNSR_ADD_CONTEXT, hasContext); if (e.verbosity >= 2) { printf("Enrolling user \"%s\"%s from file \"%s\".\n", u, hasContext? " with context": "", argv[i]); fflush(stdout); } errors = e.failed; if (snsrRun(s) == SNSR_RC_STREAM_END) snsrClearRC(s); snsrGetInt(s, SNSR_RES_ENROLLMENT_COUNT, &idx); if (idx == enrollmentIndex && errors == e.failed) { fprintf(stderr, "Enrollment skipped for \"%s\", amplitude too low?\n", e.enrollfile); e.failed++; } if (e.failed > errors) rejected++; enrollmentIndex = idx; } if (snsrRC(s) != SNSR_RC_OK) fatal(snsrRC(s), snsrErrorDetail(s)); } } if (rejected) fatal(100,"%u enrollment %s rejected.", rejected, rejected == 1? "file was": "files were"); snsrForEach(s, SNSR_USER_LIST, snsrCallback(userIterator, NULL, &e)); snsrSetString(s, SNSR_USER, NULL); /* end-of-enrollment marker */ snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM, snsrStreamFromString("")); if (snsrRun(s) == SNSR_RC_STREAM_END) snsrClearRC(s); if (snsrRC(s) != SNSR_RC_OK) fatal(snsrRC(s), snsrErrorDetail(s)); snsrRelease(s); snsrTearDown(); free((char **)e.filename); return e.failed; } ``` *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/c/wmme-stream.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/c/wmme-stream/" --- # wmme-stream.c This is the source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) implementation for [Windows Multimedia Extensions][], used for live audio capture on Windows. ## Instructions See [live-spot-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot-stream.md#live-spot-streamc). ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/c/src/wmme-stream.{c,h}_ **wmme-stream.h:** ```c /* Sensory Confidential * Copyright (C)2017-2026 Sensory, Inc. https://sensory.com/ * * TrulyHandsfree SDK custom stream header. See wmme-stream.c. *------------------------------------------------------------------------------ */ typedef enum { STREAM_LATENCY_LOW, /* low latency, high CPU overhead */ STREAM_LATENCY_HIGH, /* higher latency, with lower CPU overhead */ } StreamLatency; SnsrStream streamFromWMME(int devid, unsigned int rate, SnsrStreamMode mode, StreamLatency latency); ``` { data-search-exclude } **wmme-stream.c:** ```c /* Sensory Confidential * Copyright (C)2017-2026 Sensory, Inc. https://sensory.com/ * *------------------------------------------------------------------------------ * SnsrStream provider for Windows Multimedia Extensions Waveform Audio. * Currently capture-only. *------------------------------------------------------------------------------ */ #include #include #include #include #include #include #include #include #include #include "wmme-stream.h" /* Initial size of the circular capture buffer. 100 ms at 16kHz */ #define CAPTURE_MINSIZE 3200 /* Maximum size of the circular capture buffer. 10 s at 16kHz */ #define CAPTURE_MAXSIZE 320000 /* 15 ms at 16 kHz */ #define PERIOD_SIZE_LOW_LATENCY 240 /* 200 ms at 16 kHz */ #define PERIOD_SIZE_HIGH_LATENCY 3200 /* Minimum number of periods the buffer should include */ #define MIN_PERIOD_COUNT 3 /* Buffer size in ms */ #define MIN_BUFFER_MS 300 typedef struct { SnsrStream capture; /* Captured audio buffer */ const char *initErrorMsg; /* NULL if initialization was successful */ HWAVEIN in; /* Capture handle */ DWORD msgThreadId; /* Messaging thread ID */ WAVEFORMATEX format; /* Audio format selector */ WAVEHDR **audioChunk; /* Audio buffers */ size_t chunks; /* number of allocated audio buffers */ UINT devId; /* Capture device ID */ CONDITION_VARIABLE captureNotEmpty; CRITICAL_SECTION captureLock; } ProviderData; static void setAudioError(SnsrStream stream, SnsrRC rc, MMRESULT r, const char *tag) { #define ERRMSG_SIZE 512 char errbuf[ERRMSG_SIZE]; char *errmsg = errbuf; if (waveInGetErrorText(r, errmsg, ERRMSG_SIZE) == MMSYSERR_NOERROR) { snsrStream_setDetail(stream, "%s: %s", tag, errmsg); } else { snsrStream_setDetail(stream, "%s: error code %i", r); } snsrStream_setRC(stream, rc); } static void setLastError(SnsrStream b, const char *tag) { LPVOID lpMsgBuf; DWORD r = GetLastError(); char *m; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, r, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL); if (lpMsgBuf) { m = (char *)lpMsgBuf; m[strlen(m) - 2] = '\0'; snsrStream_setDetail(b, "%s error: %s", tag, m); LocalFree(lpMsgBuf); } else { snsrStream_setDetail(b, "%s error #%i", tag, (int)r); } snsrStream_setRC(b, SNSR_RC_ERROR); } static void audioAvailable(HWAVEIN hwi, WAVEHDR *h) { MMRESULT r = waveInUnprepareHeader(hwi, h, sizeof(*h)); ProviderData *d = (ProviderData *)h->dwUser; size_t written; EnterCriticalSection(&d->captureLock); do { if (r != MMSYSERR_NOERROR) { setAudioError(d->capture, SNSR_RC_ERROR, r, "waveInUnprepareHeader"); break; } if (!d->msgThreadId) break; assert(d->format.nChannels == 1); written = snsrStreamWrite(d->capture, h->lpData, 1, h->dwBytesRecorded); if (written != h->dwBytesRecorded) { snsrStream_setRC(d->capture, SNSR_RC_BUFFER_OVERRUN); break; } r = waveInPrepareHeader(hwi, h, sizeof(*h)); if (r != MMSYSERR_NOERROR) { setAudioError(d->capture, SNSR_RC_ERROR, r, "waveInPrepareHeader"); break; } r = waveInAddBuffer(hwi, h, sizeof(*h)); if (r != MMSYSERR_NOERROR) { waveInUnprepareHeader(hwi, h, sizeof(*h)); setAudioError(d->capture, SNSR_RC_ERROR, r, "waveInAddBuffer"); } } while (0); LeaveCriticalSection(&d->captureLock); WakeConditionVariable(&d->captureNotEmpty); } static DWORD WINAPI threadProc(LPVOID lpParameter) { BOOL r; MSG m; while ((r = GetMessage(&m, (HWND)-1, 0, 0)) > 0) { switch (m.message) { case MM_WIM_DATA: audioAvailable((HWAVEIN)m.wParam, (WAVEHDR *)m.lParam); break; case WM_QUIT: case MM_WIM_CLOSE: return ERROR_SUCCESS; } } if (r < 0) return ERROR_INVALID_HANDLE; return ERROR_SUCCESS; } /*------------------------------------------------------------------------------ */ static SnsrRC streamOpen(SnsrStream b) { ProviderData *d = (ProviderData *)snsrStream_getData(b); HANDLE th; MMRESULT r; size_t i; if (d->initErrorMsg) { snsrStream_setDetail(b, "%s", d->initErrorMsg); return SNSR_RC_NOT_FOUND; } snsrStreamOpen(d->capture); assert(!d->msgThreadId); th = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)threadProc, 0, 0, &d->msgThreadId); if (!th) { setLastError(b, "CreateThread"); return snsrStreamRC(b); } CloseHandle(th); do { r = waveInOpen(&d->in, d->devId, &d->format, (DWORD_PTR)d->msgThreadId, 0, CALLBACK_THREAD); if (r != MMSYSERR_NOERROR) { setAudioError(b, SNSR_RC_NOT_FOUND, r, "waveInOpen"); break; } for (i = 0; i < d->chunks; i++) { r = waveInPrepareHeader(d->in, d->audioChunk[i], sizeof(*d->audioChunk[i])); if (r != MMSYSERR_NOERROR) { setAudioError(b, SNSR_RC_ERROR, r, "waveInPrepareHeader"); break; } r = waveInAddBuffer(d->in, d->audioChunk[i], sizeof(*d->audioChunk[i])); if (r != MMSYSERR_NOERROR) { setAudioError(b, SNSR_RC_ERROR, r, "waveInAddBuffer"); break; } } r = waveInStart(d->in); if (r != MMSYSERR_NOERROR) setAudioError(b, SNSR_RC_ERROR, r, "waveInStart"); } while (0); if (snsrStreamRC(b) != SNSR_RC_OK) { if (d->in) { waveInClose(d->in); d->in = NULL; } if (d->msgThreadId) { PostThreadMessage(d->msgThreadId, WM_QUIT, 0, 0); d->msgThreadId = 0; } } return snsrStreamRC(b); } static SnsrRC streamClose(SnsrStream b) { ProviderData *d = (ProviderData *)snsrStream_getData(b); size_t i; /* Shut down the messaging thread. */ PostThreadMessage(d->msgThreadId, WM_QUIT, 0, 0); d->msgThreadId = 0; /* Unprepare all headers. */ waveInReset(d->in); for (i = 0; i < d->chunks; i++) { WAVEHDR *h = d->audioChunk[i]; while (waveInUnprepareHeader(d->in, h, sizeof(*h)) == WAVERR_STILLPLAYING) Sleep(10); } while (waveInClose(d->in) == WAVERR_STILLPLAYING) Sleep(10); /* Flush the capture buffer */ snsrStreamSkip(d->capture, 1, CAPTURE_MAXSIZE); snsrStream_setRC(d->capture, SNSR_RC_OK); return snsrStreamRC(b); } static void streamRelease(SnsrStream b) { ProviderData *d = (ProviderData *)snsrStream_getData(b); size_t i; snsrRelease(d->capture); if (d->audioChunk) { for (i = 0; i < d->chunks; i++) { if (d->audioChunk[i]) free(d->audioChunk[i]->lpData); free(d->audioChunk[i]); } free(d->audioChunk); } free((void *)d->initErrorMsg); free(d); } static size_t streamRead(SnsrStream b, void *buffer, size_t size) { SnsrRC r; ProviderData *d = (ProviderData *)snsrStream_getData(b); size_t read = 0; EnterCriticalSection(&d->captureLock); do { read += snsrStreamRead(d->capture, (char *)buffer + read, 1, size - read); r = snsrStreamRC(d->capture); } while ((r == SNSR_RC_OK || r == SNSR_RC_EOF) && read < size && SleepConditionVariableCS(&d->captureNotEmpty, &d->captureLock, INFINITE)); if (r != SNSR_RC_OK) { snsrStream_setRC(b, r); snsrStream_setDetail(b, "%s", snsrStreamErrorDetail(d->capture)); } else if (read < size) { snsrStream_setRC(b, SNSR_RC_EOF); } LeaveCriticalSection(&d->captureLock); return read; } static SnsrStream_Vmt ProviderDef = { "WMME audio capture", &streamOpen, &streamClose, &streamRelease, &streamRead, NULL }; SnsrStream streamFromWMME(int deviceId, unsigned int rate, SnsrStreamMode mode, StreamLatency latency) { SnsrStream b; ProviderData *d = (ProviderData *)malloc(sizeof(*d)); size_t chunkSize = 0, i; if (!d) return NULL; memset(d, 0, sizeof(*d)); b = snsrStream_alloc(&ProviderDef, d, 1, 0); if (!b) { free(d); return NULL; } do { d->devId = deviceId == -1? WAVE_MAPPER: (UINT)deviceId; d->capture = snsrStreamFromBuffer(CAPTURE_MINSIZE, CAPTURE_MAXSIZE); if (!d->capture) { snsrStream_setRC(b, SNSR_RC_NO_MEMORY); break; } snsrRetain(d->capture); if (mode != SNSR_ST_MODE_READ) { snsrStream_setRC(b, SNSR_RC_INVALID_MODE); break; } /* Signalling and mutexes */ InitializeCriticalSection(&d->captureLock); InitializeConditionVariable(&d->captureNotEmpty); /* Prepare capture format description */ d->format.wFormatTag = WAVE_FORMAT_PCM; d->format.wBitsPerSample = 16; d->format.nChannels = 1; d->format.nSamplesPerSec = rate; d->format.nBlockAlign = d->format.nChannels * d->format.wBitsPerSample / 8; d->format.nAvgBytesPerSec = d->format.nBlockAlign * d->format.nSamplesPerSec; d->format.cbSize = 0; /* Allocate buffers */ switch (latency) { case STREAM_LATENCY_LOW: chunkSize = PERIOD_SIZE_LOW_LATENCY; break; case STREAM_LATENCY_HIGH: chunkSize = PERIOD_SIZE_HIGH_LATENCY; break; } d->chunks = (int)(MIN_BUFFER_MS * rate / 1000.0 / chunkSize + 0.5); if (d->chunks < MIN_PERIOD_COUNT) d->chunks = MIN_PERIOD_COUNT; d->audioChunk = malloc(d->chunks * sizeof(*d->audioChunk)); if (!d->audioChunk) { snsrStream_setRC(b, SNSR_RC_NO_MEMORY); break; } memset(d->audioChunk, 0, d->chunks * sizeof(*d->audioChunk)); for (i = 0; i < d->chunks; i++) { d->audioChunk[i] = malloc(sizeof(**d->audioChunk)); if (!d->audioChunk[i]) { snsrStream_setRC(b, SNSR_RC_NO_MEMORY); break; } memset(d->audioChunk[i], 0, sizeof(**d->audioChunk)); d->audioChunk[i]->dwBufferLength = (DWORD)(chunkSize * sizeof(short) * d->format.nChannels); d->audioChunk[i]->lpData = malloc(d->audioChunk[i]->dwBufferLength); if (!d->audioChunk[i]->lpData) { snsrStream_setRC(b, SNSR_RC_NO_MEMORY); break; } d->audioChunk[i]->dwUser = (DWORD_PTR)d; } } while (0); if (snsrStreamRC(b) != SNSR_RC_OK) d->initErrorMsg = _strdup(snsrStreamErrorDetail(b)); return b; } ``` [Windows Multimedia Extensions]: https://learn.microsoft.com/en-us/windows/win32/api/mmeapi/nf-mmeapi-waveinopen "waveInOpen" *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[WMME]: Windows Multimedia Extensions, the audio capture API on Windows --- source_path: "api/sample/ios/index.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/ios/" --- # iOS examples The iOS sample programs are available in _sample/ios/_ in the TrulyNatural installation directory. See _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/ios/_ New to the Session API? Start with [Your first program](https://doc.sensory.com/tnl/7.8/getting-started/your-first-program.md#your-first-program) for the iOS C-via-Swift wake-word flow, then explore the sample below. ## Examples [PhraseSpot](https://doc.sensory.com/tnl/7.8/api/sample/ios/phrasespot.md#ios-ps) - Runs a wake word recognizer and shows the results in a text window. *[API]: Application Programming Interface *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/ios/phrasespot.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/ios/phrasespot/" --- # PhraseSpot This Swift application runs a phrase spotter and shows the results in a text window. ## Instructions Open _sample/ios/PhraseSpot/PhraseSpot.xcodeproj_ in [Xcode][], then choose **Run** from the **Product** menu. To run on a real device, select your Team in `General > Signing` and change `Identity > Bundle Identifier` to match your development domain. The app starts listening for "hello blue genie" upon startup. Say this trigger phrase to see the recognizer response. ## Code This application uses the native C API of the TrulyNatural SDK by using a Swift [bridging header][]. Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/ios/PhraseSpot/PhraseSpot/PhraseSpot.swift_ **PhraseSpot.swift:** ```swift // // PhraseSpot.swift // PhraseSpot // // Copyright © 2018-2026 Sensory, Inc. https://sensory.com/ // All rights reserved. // import Foundation import AVFoundation protocol PhraseSpotDelegate: AnyObject { func recogniserWillStart() func recognizerDidStop(code: SnsrRC, message: String) func recognizerDidSpot(text: String, beginMs: Double, endMs: Double) } enum PhraseSpotError: Error { case api(code: SnsrRC, message: String) } class PhraseSpot { //MARK: Nested classes enum State { case stopped, started, paused } //MARK: Private properties private var session: SnsrSession? private var audio: SnsrStream? private var rC: SnsrRC = SNSR_RC_OK //MARK: Properties var libraryInfo: String? weak var delegate: PhraseSpotDelegate? var state: State = .stopped { didSet { if state == .started { startRecog() } } } //MARK: Initialization init(modelName: String) throws { try load(modelName: modelName) } deinit { if state == .started { stop() } release(&session) release(&audio) } //MARK: Private methods // C library wrappers, for convenience private func release(_ ptr: inout Optional) { snsrRelease(UnsafeRawPointer(ptr)) ptr = nil } private func retain(_ ptr: Optional) { snsrRetain(UnsafeRawPointer(ptr)) } // Find a model in the applications main bundle. private func modelPath(_ modelName: String) -> String { guard let path = Bundle.main.path(forResource: modelName, ofType: "snsr", inDirectory: "models") else { return modelName } return path } // Create and throw a PhraseSpotError.api private func throwIfError(_ session: SnsrSession?) throws { let rc = snsrRC(session) if (rc != SNSR_RC_OK) { let msg = String(cString: snsrErrorDetail(session)) print(msg) throw PhraseSpotError.api(code: rc, message: msg) } } private func load(modelName: String) throws { snsrNewIncludeOSS(&session, SNSR_VERSION) try throwIfError(session) var libInfo: UnsafePointer? snsrGetString(session, SNSR_LIBRARY_INFO, &libInfo) try throwIfError(session) libraryInfo = String(cString: libInfo!) snsrLoad(session, snsrStreamFromFileName(modelPath(modelName), "r")) snsrRequire(session, SNSR_TASK_TYPE, SNSR_PHRASESPOT) snsrRequire(session, SNSR_TASK_VERSION, "~0.5.0 || 1.0.0") // Convert self into a pointer to pass to the C library let selfPtr = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()) // Report recognition results with a delegate.recognizerDidSpot() snsrSetHandler(session, SNSR_RESULT_EVENT, snsrCallback({ (session, key, selfPtr) -> SnsrRC in let my = Unmanaged.fromOpaque(selfPtr!).takeUnretainedValue() var text: UnsafePointer? var beginMs: Double = 0 var endMs: Double = 0 snsrGetString(session, SNSR_RES_TEXT, &text) snsrGetDouble(session, SNSR_RES_BEGIN_MS, &beginMs) snsrGetDouble(session, SNSR_RES_END_MS, &endMs) let spot = String(cString: text!) DispatchQueue.main.sync { my.delegate?.recognizerDidSpot(text: spot, beginMs: beginMs, endMs: endMs) } return SNSR_RC_OK }, nil, selfPtr)) // Stop background recognition if the state changes from .started snsrSetHandler(session, SNSR_SAMPLES_EVENT, snsrCallback({ (session, key, selfPtr) -> SnsrRC in let my = Unmanaged.fromOpaque(selfPtr!).takeUnretainedValue() return my.state == .started ? SNSR_RC_OK : SNSR_RC_STOP }, nil, selfPtr)) // Allow Bluetooth headsets try AVAudioSession.sharedInstance() .setCategory(.playAndRecord, options: AVAudioSession.CategoryOptions.allowBluetooth) // Live audio audio = snsrStreamFromDefaultAudioDevice() retain(audio) snsrSetStream(session, SNSR_SOURCE_AUDIO_PCM, audio) try throwIfError(session) } // Run phrase spotter on a background thread private func startRecog() { snsrClearRC(session) self.delegate?.recogniserWillStart() DispatchQueue.global(qos: .background).async { let code = snsrRun(self.session) // Stop recording when we are not spotting snsrStreamClose(self.audio) let msg = String(cString: snsrErrorDetail(self.session)) DispatchQueue.main.sync { self.delegate?.recognizerDidStop(code: code, message: msg) } } } //MARK: Public methods // Change scalar SnsrSession settings func set(_ key: String, _ value: Double) throws { let code = snsrSetInt(session, key, Int32(value)) if code == SNSR_RC_INCORRECT_SETTING_TYPE { snsrClearRC(session) snsrSetDouble(session, key, value) } try throwIfError(session) } // Start the phrase spotter func start() { if state != .started { state = .started } } // Stop the recognizer func stop() { if state != .stopped { state = .stopped } } // Pause a running spotter func pause() { if state == .started { state = .paused } } // Resume a paused spotter func resume() { if state == .paused { state = .started } } } ``` [bridging header]: https://developer.apple.com/documentation/swift/importing-objective-c-into-swift "Importing Objective-C into Swift" [Xcode]: https://developer.apple.com/xcode/ "Xcode enables you to develop, test, and distribute apps for all Apple platforms" *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/java/SnsrEnrollmentTest.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/java/SnsrEnrollmentTest/" --- # SnsrEnrollmentTest.java This file contains UDT enrollment and evaluation unit tests. It shows how to remove an enrollment from an enrollment context loaded from file. ## Instructions To run these tests, open a terminal window and enter the commands after the `%` prompt below (on Windows, replace `./gradlew` with `gradlew.bat`). ```console % cd ~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/java/enroll-udt/ % ./gradlew test BUILD SUCCESSFUL in 7s 6 actionable tasks: 6 executed ``` ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/java/enroll-udt/src/test/java/SnsrEnrollmentTest.java_ **SnsrEnrollmentTest.java:** ```java /* Sensory Confidential * Copyright (C)2017-2026 Sensory, Inc. https://sensory.com/ * * Unit tests for UDT enrollment and generated spotter tasks. *------------------------------------------------------------------------------ */ package com.sensory.speech.snsr.test; import java.io.IOException; import java.util.*; import org.junit.Test; import static org.junit.Assert.*; import org.junit.*; import org.junit.runners.MethodSorters; import com.sensory.speech.snsr.*; import enroll.BuildConfig; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class SnsrEnrollmentTest { final String EnrollmentContext = BuildConfig.MODEL_DIR + "/test-enrollment-context.snsr"; final String SvModel1 = BuildConfig.MODEL_DIR + "/test-1.snsr"; final String SvModel2 = BuildConfig.MODEL_DIR + "/test-2.snsr"; final String[] Users = { "armadillo-1", "jackalope-1" }; final String[] TestUsers = { "armadillo-1", "armadillo-6", "jackalope-1", "jackalope-4", "terminator-2", "terminator-6" }; // Enroll two users from file. // Save the adapted enrollment context to file. // This test has to run before enrollFromContext* @Test public void EnrollFromFile() { SnsrSession s = new SnsrSession(); try { s .load(BuildConfig.UDT_MODEL) .require(Snsr.TASK_TYPE, Snsr.ENROLL) .setHandler(Snsr.DONE_EVENT, (session, key) -> { // Save enrolled model for further testing SnsrStream out = SnsrStream.fromFileName(SvModel2, "w"); try { out.copy(session.getStream(Snsr.MODEL_STREAM)); out.close(); } catch (IOException e) { fail(e.toString()); } System.out.println("Enrolled model saved to " + SvModel2); return SnsrRC.OK; }) .setHandler(Snsr.PROG_EVENT, (session, key) -> { double p = session.getDouble(Snsr.RES_PERCENT_DONE); System.out.println(String.format("Adapting: %3.0f%% done.", p)); return SnsrRC.OK; }) // Prepare for non-interactive enrollment .setInt(Snsr.INTERACTIVE_MODE, 0); // Enroll example users for (String tag: Users) { s.setString(Snsr.USER, tag); for (int i = 0; i < 4; i++) { final String path = String.format("%s/%s-%d.wav", BuildConfig.ENROLLMENT_DIR, tag, i); SnsrStream a = SnsrStream.fromAudioFile(path, "r"); s .setStream(Snsr.SOURCE_AUDIO_PCM, a) .run(); assertEquals(SnsrRC.STREAM_END, s.rC()); System.out.println("Enrolled " + tag + " with " + path); } } // List enrolled users s.forEach(Snsr.USER_LIST, (session, key) -> { System.out.println("Enrolled: " + session.getString(Snsr.USER)); return SnsrRC.OK; }); // End-of-enrollment markers s .setString(Snsr.USER, null) .setStream(Snsr.SOURCE_AUDIO_PCM, SnsrStream.fromString("")); assertEquals(SnsrRC.OK, s.rC()); s.run(); assertEquals(SnsrRC.STREAM_END, s.rC()); // Save adapted enrollment context s.save(SnsrDataFormat.RUNTIME, EnrollmentContext); } catch (IOException e) { fail(e.toString()); } s.release(); } // Load the adapted enrollment context created by "enrollment" above. @Test public void enrollFromContext() { SnsrSession s = new SnsrSession(); try { s .load(BuildConfig.UDT_MODEL) .require(Snsr.TASK_TYPE, Snsr.ENROLL) // Load the enrollment context after loading the primary model .load(EnrollmentContext) // Prepare for non-interactive enrollment .setInt(Snsr.INTERACTIVE_MODE, 0); // List enrolled users final List enrolledUsers = new ArrayList(); s.forEach(Snsr.USER_LIST, (session, key) -> { enrolledUsers.add(session.getString(Snsr.USER)); return SnsrRC.OK; }); assertEquals(Arrays.toString(Users), enrolledUsers.toString()); // End-of-enrollment markers s .setString(Snsr.USER, null) .setStream(Snsr.SOURCE_AUDIO_PCM, SnsrStream.fromString("")); assertEquals(SnsrRC.OK, s.rC()); s.run(); assertEquals(SnsrRC.STREAM_END, s.rC()); } catch (IOException e) { fail(e.toString()); } s.release(); } // Load the adapted enrollment context created by "enrollment" above. // Remove one user, re-adapt. @Test public void enrollFromContextRemoveOne() { SnsrSession s = new SnsrSession(); try { s .load(BuildConfig.UDT_MODEL) .require(Snsr.TASK_TYPE, Snsr.ENROLL) // Load the enrollment context after loading the primary model .load(EnrollmentContext) // Prepare for non-interactive enrollment .setInt(Snsr.INTERACTIVE_MODE, 0) // Save enrolled model for further testing .setHandler(Snsr.DONE_EVENT, (session, key) -> { SnsrStream out = SnsrStream.fromFileName(SvModel1, "w"); try { out.copy(session.getStream(Snsr.MODEL_STREAM)); out.close(); } catch (IOException e) { fail(e.toString()); } System.out.println("Enrolled model saved to " + SvModel1); return SnsrRC.OK; }) // Remove the first enrollment .setString(Snsr.DELETE_USER, Users[0]); // List enrolled users final List enrolledUsers = new ArrayList(); s.forEach(Snsr.USER_LIST, (session, key) -> { enrolledUsers.add(session.getString(Snsr.USER)); return SnsrRC.OK; }); assertEquals(Arrays.toString(Arrays.copyOfRange(Users, 1, Users.length)), enrolledUsers.toString()); // End-of-enrollment markers s .setString(Snsr.USER, null) .setStream(Snsr.SOURCE_AUDIO_PCM, SnsrStream.fromString("")); assertEquals(SnsrRC.OK, s.rC()); s.run(); assertEquals(SnsrRC.STREAM_END, s.rC()); } catch (IOException e) { fail(e.toString()); } s.release(); } // Load the adapted enrollment context created by "enrollment" above. // Remove two users, re-adapt. @Test public void enrollFromContextRemoveTwo() { SnsrSession s = new SnsrSession(); // Holder for DONE_EVENT count final int[] doneEventCount = new int[1]; try { s .load(BuildConfig.UDT_MODEL) .require(Snsr.TASK_TYPE, Snsr.ENROLL) // Load the enrollment context after loading the primary model .load(EnrollmentContext) // Prepare for non-interactive enrollment .setInt(Snsr.INTERACTIVE_MODE, 0) .setHandler(Snsr.DONE_EVENT, (session, key) -> { // Invoked for each deleted user doneEventCount[0]++; return SnsrRC.STOP; }); // Remove the first enrollment doneEventCount[0] = 0; s .setString(Snsr.DELETE_USER, Users[0]) .setString(Snsr.DELETE_USER, Users[1]); assertEquals(SnsrRC.STOP, s.rC()); assertEquals(doneEventCount[0], 2); // List enrolled users final List enrolledUsers = new ArrayList(); s.forEach(Snsr.USER_LIST, (session, key) -> { enrolledUsers.add(session.getString(Snsr.USER)); return SnsrRC.OK; }); assertEquals(Arrays.toString(Arrays.copyOfRange(Users, 2, Users.length)), enrolledUsers.toString()); // End-of-enrollment markers s .setString(Snsr.USER, null) .setStream(Snsr.SOURCE_AUDIO_PCM, SnsrStream.fromString("")); assertEquals(SnsrRC.OK, s.rC()); s.run(); assertEquals(SnsrRC.STREAM_END, s.rC()); } catch (IOException e) { fail(e.toString()); } s.release(); } // Returns SnsrStream concatenation of test files. private SnsrStream testAudioStream() { SnsrStream c = SnsrStream.fromString(""); for (String tag: TestUsers) { for (int i = 4; i <= 5; i++) { final String path = String.format("%s/%s-%d.wav", BuildConfig.ENROLLMENT_DIR, tag, i); c = SnsrStream.fromStreams(c, SnsrStream.fromAudioFile(path, "r")); } } return c; } // Evaluate model created by enrollFromContextRemoveOne() // Just jackalope-1 should spot, as armadillo-1 was removed. @Test public void evalModelOneUser() { SnsrSession s = new SnsrSession(); final List result = new ArrayList(); try { s .load(SvModel1) .require(Snsr.TASK_TYPE, Snsr.PHRASESPOT) .setHandler(Snsr.RESULT_EVENT, (session, key) -> { result.add(session.getString(Snsr.RES_TEXT)); return SnsrRC.OK; }) .setStream(Snsr.SOURCE_AUDIO_PCM, testAudioStream()) .run() .release(); } catch (IOException e) { fail(e.toString()); } assertEquals("[jackalope-1, jackalope-1]", result.toString()); } // Evaluate model created by EnrollFromContext(). // Both armadillo-1 and jackalope-1 should spot. @Test public void evalModelTwoUsers() { SnsrSession s = new SnsrSession(); final List result = new ArrayList(); try { s .load(SvModel2) .require(Snsr.TASK_TYPE, Snsr.PHRASESPOT) .setHandler(Snsr.RESULT_EVENT, (session, key) -> { result.add(session.getString(Snsr.RES_TEXT)); return SnsrRC.OK; }) .setStream(Snsr.SOURCE_AUDIO_PCM, testAudioStream()) .run() .release(); } catch (IOException e) { fail(e.toString()); } assertEquals("[armadillo-1, armadillo-1, jackalope-1, jackalope-1]", result.toString()); } } ``` *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets --- source_path: "api/sample/java/SnsrStreamAudioDeviceGeneric.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/java/SnsrStreamAudioDeviceGeneric/" --- # SnsrStreamAudioDeviceGeneric.java This is the source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) implementation for Java. It provides a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) adapter for [Java Audio][]. **Also see these related items:** [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/java/misc/SnsrStreamAudioDeviceGeneric.java_ **SnsrStreamAudioDeviceGeneric.java:** ```java /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ * * Generic audio recording to read-only SnsrStream adapter. *------------------------------------------------------------------------------ */ package com.sensory.speech.snsr; import java.io.IOException; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Line; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.Mixer; import javax.sound.sampled.TargetDataLine; import com.sensory.speech.snsr.SnsrStream; /* * Implements the SnsrStream.Provider interface for live audio. * * Create a new SnsrStream instance with: * SnsrStream a = SnsrStream.fromProvider(new SnsrStreamAudioDeviceGeneric(16000), * SnsrStreamMode.READ); */ class SnsrStreamAudioDeviceGeneric implements SnsrStream.Provider { private TargetDataLine mInput; private AudioFormat mAudioFormat; public SnsrStreamAudioDeviceGeneric(int sampleRate) { mInput = getDefaultMicrophone(); mAudioFormat = new AudioFormat((float) sampleRate, 16, 1, true, false); } @Override public long onOpen() throws IOException { if (mInput == null) return NOT_OPEN; try { mInput.open(mAudioFormat); mInput.start(); } catch (LineUnavailableException e) { throw new IOException(e.toString()); } return OK; } @Override public long onClose() throws IOException { mInput.stop(); mInput.close(); return OK; } @Override public void onRelease() { mInput = null; } @Override public long onRead(byte[] buffer) throws IOException { long read = mInput.read(buffer, 0, buffer.length); if (Thread.interrupted()) return INTERRUPTED; return read; } @Override public long onWrite(byte[] buffer) throws IOException { return NOT_IMPLEMENTED; } /* Find the default system microphone */ private TargetDataLine getDefaultMicrophone() { Mixer.Info[] mixers = AudioSystem.getMixerInfo(); for (Mixer.Info mixerInfo : mixers) { Mixer m = AudioSystem.getMixer(mixerInfo); try { m.open(); m.close(); } catch (Exception e) { continue; } Line.Info[] lines = m.getTargetLineInfo(); for (Line.Info l : lines) { try { TargetDataLine t = (TargetDataLine) AudioSystem.getLine(l); if (t!= null) return t; } catch (Exception e) { /* ignore */ } } } return null; } } ``` [Java Audio]: https://docs.oracle.com/javase/tutorial/sound/capturing.html "Audio capturing in Java" *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/sample/java/enrollUDT.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/java/enrollUDT/" --- # enrollUDT.java This example shows how to enroll a user-defined wake word (UDT, trigger, key word spotter). ## Instructions To run this example, choose a wake word phrase, open a terminal window and enter the commands after the `%` prompt below (on Windows, replace `./gradlew` with `gradlew.bat`). Speak when prompted. ```console % cd ~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/java/enroll-udt/ % ./gradlew -q --console=plain enroll Please say your enrollment phrase (1/4) Recording: 3.80 s Recording passes preliminary tests. Please say your enrollment phrase (2/4) Recording: 3.60 s Recording passes preliminary tests. Please say your enrollment phrase (3/4) with context, for example: " will it rain tomorrow?" Recording: 5.01 s Recording passes preliminary tests. Please say your enrollment phrase (4/4) with context, for example: " will it rain tomorrow?" Recording: 4.31 s Recording passes preliminary tests. Adapting: 100% done. Enrollment context saved to ~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/java/enroll-udt/build/model/enrollment-context.snsr Enrolled model saved to ~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/java/enroll-udt/build/model/enrolled-sv.snsr Done! ``` You can make additional enrollments by specifying a unique phrase tag on the command line. New enrollments replace previous ones that used the same `tag`. ```console % ./gradlew -q --console=plain enroll -Ptag=second-phrase ``` Use the `eval` target to test the wake word enrollment(s) (**Also see these related items:** [evalUDT.java](https://doc.sensory.com/tnl/7.8/api/sample/java/evalUDT.md#evaludtjava)). Stop the process with `^C` when you're done. ```console % ./gradlew -q --console=plain eval Say your enrolled phrase. #00 "custom-phrase", score = 0.817 [12795 ms, 13875 ms] custom-phrase Recording: 16.91 ^C ``` To start over, remove the existing enrollments: ```console % ./gradlew -q --console=plain clean ``` ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/java/enroll-udt/src/main/java/com/sensory/speech/snsr/demo/enroll-udt/enrollUDT.java_ **enrollUDT.java:** ```java /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ * * Command-line User-Defined Trigger enrollment. *------------------------------------------------------------------------------ */ import java.io.Console; import java.io.IOException; import com.sensory.speech.snsr.Snsr; import com.sensory.speech.snsr.SnsrDataFormat; import com.sensory.speech.snsr.SnsrRC; import com.sensory.speech.snsr.SnsrSession; import com.sensory.speech.snsr.SnsrStream; import enroll.BuildConfig; public class enrollUDT { public static void main(String argv[]) { final int SAMPLE_RATE = 16000; final String SpeakNow = "\nPlease say your enrollment phrase"; final String EnrollmentContext = BuildConfig.MODEL_DIR + "/enrollment-context.snsr"; String userTag = "custom-phrase"; if (argv.length == 1) userTag = argv[0]; else if (argv.length != 0) { System.out.println("usage: ./gradlew enroll [-Ptag=user-or-phrase-tag]"); System.exit(7); } // Live audio stream handle. SnsrStream audio = SnsrStream.fromAudioDevice(); // Primary TrulyHandsfree session handle. SnsrSession s = new SnsrSession(); try { s.load(BuildConfig.UDT_MODEL).require(Snsr.TASK_TYPE, Snsr.ENROLL); } catch (IOException e) { e.printStackTrace(); System.exit(3); } try { s.load(EnrollmentContext); try { s.setString(Snsr.DELETE_USER, userTag); } catch (Exception e) { } System.out.println("Loaded enrollments from " + EnrollmentContext); s.forEach(Snsr.USER_LIST, (ses, key) -> { System.out.println("User " + ses.getString(Snsr.USER) + " has " + ses.getInt(Snsr.RES_ENROLLMENT_COUNT) + " enrollments."); return SnsrRC.OK; }); } catch (IOException e) { // ignore } s.setStream(Snsr.SOURCE_AUDIO_PCM, audio) .setString(Snsr.USER, userTag) .setHandler(Snsr.FAIL_EVENT, (ses, key) -> { System.out.println("This enrollment recording is not usable."); System.out.println(" Reason: " + ses.getString(Snsr.RES_REASON)); System.out.println(" Fix: " + ses.getString(Snsr.RES_GUIDANCE)); return SnsrRC.OK; }) .setHandler(Snsr.PASS_EVENT, (ses, key) -> { System.out.println("Recording passes preliminary tests."); return SnsrRC.OK; }) .setHandler(Snsr.PROG_EVENT, (ses, key) -> { double p = ses.getDouble(Snsr.RES_PERCENT_DONE); System.out.print(String.format("\rAdapting: %3.0f%% done. ", p)); if (p >= 100) System.out.println(""); return SnsrRC.OK; }) .setHandler(Snsr.PAUSE_EVENT, (ses, key) -> { // Pause recording while processing. System.out.println(""); audio.close(); return SnsrRC.OK; }) .setHandler(Snsr.RESUME_EVENT, (ses, key) -> { try { // Restart recording. audio.open(); } catch (Exception e) { e.printStackTrace(); } String prompt = SpeakNow + " (" + (ses.getInt(Snsr.RES_ENROLLMENT_COUNT) + 1) + "/" + ses.getInt(Snsr.ENROLLMENT_TARGET) + ")"; if (ses.getInt(Snsr.ADD_CONTEXT) != 0) { prompt += " with context,\n for example: " + "\" will it rain tomorrow?\""; } System.out.println(prompt); return SnsrRC.OK; }) .setHandler(Snsr.DONE_EVENT, (ses, key) -> { SnsrStream out = SnsrStream.fromFileName(BuildConfig.ENROLLED_MODEL, "w"); try { out.copy(ses.getStream(Snsr.MODEL_STREAM)); System.out.println("Enrolled model saved to " + BuildConfig.ENROLLED_MODEL); } catch (Exception e) { e.printStackTrace(); } out.close(); System.out.println("Done!"); return SnsrRC.STOP; }) // Optional: save enrollment context // Use Snsr.ENROLLED_EVENT to save the // unadapted enrollment context instead. .setHandler(Snsr.ADAPTED_EVENT, (ses, key) -> { ses.save(SnsrDataFormat.RUNTIME, EnrollmentContext); System.out.println("Enrollment context saved to " + EnrollmentContext); return SnsrRC.OK; }) // Show audio recording duration .setHandler(Snsr.SAMPLES_EVENT, (ses, key) -> { double count = ses.getDouble(Snsr.RES_SAMPLES); System.out.print(String.format("\rRecording: %6.2f s ", count / SAMPLE_RATE)); return SnsrRC.OK; }); try { s.run(); // Optional but good practice. finalize() will (eventually) release. s.release(); audio.release(); } catch (IOException e) { e.printStackTrace(); } } } ``` *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets --- source_path: "api/sample/java/evalUDT.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/java/evalUDT/" --- # evalUDT.java This example shows how to run a wake word recognizer. It uses the UDT phrase enrolled with [enrollUDT.java](https://doc.sensory.com/tnl/7.8/api/sample/java/enrollUDT.md#enrolludtjava). ## Instructions Enroll a custom wake word as outlined in [enrollUDT.java](https://doc.sensory.com/tnl/7.8/api/sample/java/enrollUDT.md#enrolludt-instructions). Open a terminal window and enter the commands after the `%` prompt below (on Windows, replace `./gradlew` with `gradlew.bat`). Speak when prompted. Stop the process with `^C` when you're done. ```console % cd ~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/java/enroll-udt/ % ./gradlew -q --console=plain eval Say your enrolled phrase. #00 "custom-phrase", score = 0.700 [2505 ms, 3480 ms] custom-phrase #01 "custom-phrase", score = 0.636 [6660 ms, 7425 ms] custom-phrase #02 "custom-phrase", score = 0.668 [11475 ms, 12525 ms] custom-phrase Recording: 14.50 ^C ``` ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/java/enroll-udt/src/main/java/com/sensory/speech/snsr/demo/enroll-udt/evalUDT.java_ **evalUDT.java:** ```java /* Sensory Confidential * Copyright (C)2016-2026 Sensory, Inc. https://sensory.com/ * * Command-line phrase spotter. *------------------------------------------------------------------------------ */ import java.io.Console; import java.io.File; import java.io.IOException; import com.sensory.speech.snsr.Snsr; import com.sensory.speech.snsr.SnsrRC; import com.sensory.speech.snsr.SnsrSession; import com.sensory.speech.snsr.SnsrStream; import enroll.BuildConfig; public class evalUDT { public static void main(String argv[]) { final int TIMEOUT = 60; final int SAMPLE_RATE = 16000; // Check whether the enrolled spotter model exists if (!(new File(BuildConfig.ENROLLED_MODEL).exists())) { System.out.println("Enrollment model file " + BuildConfig.ENROLLED_MODEL); System.out.println("was not found. Please enroll a phrase by running:" + "./gradlew -q enroll"); System.exit(1); } // Holder for the number of spots encountered so far final int[] spotCount = new int[1]; // Spot from live audio SnsrStream audio = SnsrStream.fromAudioDevice(); // Primary TrulyHandsfree session handle SnsrSession s = new SnsrSession(); try { s.load(BuildConfig.ENROLLED_MODEL); } catch (IOException e) { e.printStackTrace(); System.exit(3); } s.require(Snsr.TASK_TYPE, Snsr.PHRASESPOT) // .setDouble(Snsr.SV_THRESHOLD, 0.1) // test - override default .setStream(Snsr.SOURCE_AUDIO_PCM, audio) // Show the duration of processed audio, // and stop after TIMEOUT seconds .setHandler(Snsr.SAMPLES_EVENT, (ses, key) -> { double count = ses.getDouble(Snsr.RES_SAMPLES); System.out.print(String.format("\rRecording: %6.2f s", count / SAMPLE_RATE)); if (count < SAMPLE_RATE * TIMEOUT) return SnsrRC.OK; return SnsrRC.TIMED_OUT; }) // Phrase spot event. Show speaker verification score and alignments. .setHandler(Snsr.RESULT_EVENT, (ses, key) -> { System.out.println(String.format("\r#%02d \"%s\", score = %.3f", spotCount[0]++, ses.getString("text"), ses.getDouble("sv-score"))); // Replace Snsr.WORD_LIST with Snsr.PHONE_LIST to show phonemes ses.forEach(Snsr.WORD_LIST, (s2, key2) -> { System.out.println(String.format(" [%.0f ms, %.0f ms] %s", s2.getDouble(Snsr.RES_BEGIN_MS), s2.getDouble(Snsr.RES_END_MS), s2.getString(Snsr.RES_TEXT))); return SnsrRC.OK; }); System.out.println(""); return SnsrRC.OK; }); // Show an SDK license expiration warning, if needed final String licenseWarning = s.getString(Snsr.LICENSE_WARNING); if (licenseWarning != null) System.out.println(licenseWarning); System.out.println("Say your enrolled phrase."); try { s.run(); s.release(); audio.release(); } catch (IOException e) { e.printStackTrace(); } System.out.println("\nDone."); } } ``` *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets --- source_path: "api/sample/java/index.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/java/" --- # Java examples The Java sample programs and code snippets are available in _sample/java/_ in the TrulyNatural installation directory. See _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/java/_ New to the Session API? Start with [Your first program](https://doc.sensory.com/tnl/7.8/getting-started/your-first-program.md#your-first-program) (`FirstSpot.java`), then explore the samples below. ## Examples [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudiojava) - Runs a wake word followed by a VAD, and saves the captured audio to file. [enrollUDT.java](https://doc.sensory.com/tnl/7.8/api/sample/java/enrollUDT.md#enrolludtjava) - Enrolls a user-defined wake word. [evalUDT.java](https://doc.sensory.com/tnl/7.8/api/sample/java/evalUDT.md#evaludtjava) - Runs the wake word enrolled by [enrollUDT.java](https://doc.sensory.com/tnl/7.8/api/sample/java/enrollUDT.md#enrolludtjava). [SnsrEnrollmentTest.java](https://doc.sensory.com/tnl/7.8/api/sample/java/SnsrEnrollmentTest.md#snsrenrollmenttestjava) - Unit tests for UDT enrollment and evaluation. [SnsrStreamAudioDeviceGeneric.java](https://doc.sensory.com/tnl/7.8/api/sample/java/SnsrStreamAudioDeviceGeneric.md#snsrstreamaudiodevicegenericjava) - Source for the [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) implementation for [Java Audio][]. [Java Audio]: https://docs.oracle.com/javase/tutorial/sound/capturing.html "Audio capturing in Java" *[API]: Application Programming Interface *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets *[VAD]: Voice Activity Detector --- source_path: "api/sample/java/segmentSpottedAudio.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio/" --- # segmentSpottedAudio.java This example runs a phrase spotter followed by a VAD. It saves the VAD-segmented audio to file. ## Instructions To run this example, open a terminal window and enter the commands after the `%` prompt below (on Windows, replace `./gradlew` with `gradlew.bat`). Speak when prompted. ```console % cd ~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/java/enroll-udt/ % ./gradlew -q --console=plain segment Say: "Hello Blue Genie will it rain in Portland tomorrow?" Found "hello blue genie"... listening VAD start detected. VAD endpoint ^end Found speech from 6990.000 ms to 8505.000 ms Wrote recording to "vad-audio.wav" ``` _vad-audio.wav_ captured above includes only the speech following the "Hello Blue Genie" wake word. You can change this to also include the wake word audio by setting the `include-spot` property: ```console % ./gradlew -q --console=plain segment -Pinclude-spot Say: "Hello Blue Genie will it rain in Portland tomorrow?" Found "hello blue genie"... listening VAD start detected. VAD endpoint ^end Found speech from 1620.000 ms to 3960.000 ms Wrote recording to "vad-audio.wav" ``` ## Code Available in this TrulyNatural SDK installation at _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/java/enroll-udt/src/main/java/com/sensory/speech/snsr/demo/enroll-udt/segmentSpottedAudio.java_ **segmentSpottedAudio.java:** ```java /* Sensory Confidential * Copyright (C)2017-2026 Sensory, Inc. https://sensory.com/ * * Command-line phrase spotter, runs trailing audio through VAD * and saves this speech-detected audio to file. *------------------------------------------------------------------------------ */ import java.io.Console; import java.io.File; import java.io.IOException; import com.sensory.speech.snsr.Snsr; import com.sensory.speech.snsr.SnsrRC; import com.sensory.speech.snsr.SnsrSession; import com.sensory.speech.snsr.SnsrStream; import enroll.BuildConfig; public class segmentSpottedAudio { public static void main(String argv[]) { final String VAD_AUDIO_FILE = "vad-audio.wav"; final Boolean INCLUDE_SPOT = (argv.length == 1); // Spot from live audio SnsrStream audio = SnsrStream.fromAudioDevice(); // Primary TrulyHandsfree session handle SnsrSession s = new SnsrSession(); try { // Load and validate the spot-vad template model. s.load(BuildConfig.VAD_TEMPLATE); s.require(Snsr.TASK_TYPE, Snsr.PHRASESPOT_VAD); // Fill in slot #0 with a phrase spotter. s.setStream(Snsr.SLOT_0, SnsrStream.fromFileName(BuildConfig.HBG_MODEL, "r")); } catch (IOException e) { e.printStackTrace(); System.exit(3); } // Output file for VAD-selected audio. SnsrStream out = SnsrStream.fromAudioFile(VAD_AUDIO_FILE, "w"); // Configure session s.setStream(Snsr.SOURCE_AUDIO_PCM, audio) .setStream(Snsr.SINK_AUDIO_PCM, out) .setInt(Snsr.INCLUDE_LEADING_SILENCE, INCLUDE_SPOT ? 1 : 0) .setInt(Snsr.BACKOFF, 0) // reduce VAD audio margins to the minimum .setInt(Snsr.HOLD_OVER, 0) // Phrase spot event. .setHandler(Snsr.RESULT_EVENT, (session, key) -> { System.out.println(String.format("Found \"%s\"... listening", session.getString("text"))); return SnsrRC.OK; }); // VAD endpoint callback SnsrSession.Listener endpoint = (ses, key) -> { double from = ses.getDouble(Snsr.RES_BEGIN_MS); double to = ses.getDouble(Snsr.RES_END_MS); final String msg = String.format("Found speech from %.3f ms to %.3f ms", from, to); System.out.println("VAD endpoint " + key + "\n" + msg); // Stop after one VAD endpoint detection. return SnsrRC.STOP; }; // Wire up handlers for the VAD events. s.setHandler(Snsr.END_EVENT, endpoint) .setHandler(Snsr.LIMIT_EVENT, endpoint) .setHandler(Snsr.BEGIN_EVENT, (session, key) -> { System.out.println("VAD start detected."); return SnsrRC.OK; }) .setHandler(Snsr.SILENCE_EVENT, (session, key) -> { System.out.println("VAD endpoint " + key + "\n" + "Listening for \"Hello Blue Genie\"."); return SnsrRC.OK; }); // Show an SDK license expiration warning, if needed final String licenseWarning = s.getString(Snsr.LICENSE_WARNING); if (licenseWarning != null) System.out.println(licenseWarning); System.out.println("Say: \"Hello Blue Genie will it rain " + "in Portland tomorrow?\""); try { s.run(); } catch (IOException e) { e.printStackTrace(); System.exit(4); } s.release(); out.release(); System.out.println("Wrote recording to \"" + VAD_AUDIO_FILE + "\""); } } ``` *[API]: Application Programming Interface *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets *[VAD]: Voice Activity Detector --- source_path: "api/setting-keys/configuration.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration/" --- # Configuration Configuration settings are both readable and writable and are part of task models; they are saved to [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) by [dup](https://doc.sensory.com/tnl/7.8/api/inference.md#dup) and [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save), and restored by [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load). Use these to change model or fine-tune model behavior. Models have reasonable defaults, so most applications set no configuration keys at runtime — defaults are baked into the `.snsr` model file at training time. Most salient are [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) for wake words and command sets, [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence) and [trailing-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#trailing-silence) for VAD templates, [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval) for LVCSR and STT, and [stt-profile](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#stt-profile) for STT models. Common reasons applications *do* override configuration include enrollment (see [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user), [interactive](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#interactive)), THF Micro export (see [dsp-target](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-target)), and selecting an active template slot in multi-stage models (see [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot)). Use the [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) `get` and `set` functions that match the type of the setting. Use [getInt](https://doc.sensory.com/tnl/7.8/api/inference.md#getters), for example, to read the _(int)_ value for [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point). ### Details: Page conventions Settings are grouped by concern. Within each group they're listed alphabetically. A setting that serves more than one concern appears once under its primary group; secondary groups link to it. ## Audio I/O ### audio-stream-size - configuration - int - read-write **C/C++** ```c #define SNSR_AUDIO_STREAM_SIZE "audio-stream-size" ``` **Java** ```java public class Snsr { public final static String AUDIO_STREAM_SIZE = "audio-stream-size"; } ``` Input audio buffer size. The number of audio samples kept in a circular audio history buffer, accessible through [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream). Use this buffer to retrieve segmented audio using alignments ([begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms)) obtained in the [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result). Set to `0` to disable audio buffering. **Also see these related items:** [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream) ### samples-per-second - configuration - int - read-only **C/C++** ```c #define SNSR_SAMPLE_RATE "samples-per-second" ``` **Java** ```java public class Snsr { public final static String SAMPLE_RATE = "samples-per-second"; } ``` Model sample rate in Hz. ## VAD & endpointing ### backoff - configuration - int - read-write **C/C++** ```c #define SNSR_BACKOFF "backoff" ``` **Java** ```java public class Snsr { public final static String BACKOFF = "backoff"; } ``` Start point back-off in ms. Audio margin added before the start point found by a VAD. **Also see these related items:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample) ### hold-over - configuration - int - read-write **C/C++** ```c #define SNSR_HOLD_OVER "hold-over" ``` **Java** ```java public class Snsr { public final static String HOLD_OVER = "hold-over"; } ``` Endpoint hold-over. Audio margin added after the endpoint found by a VAD. This is the amount of trailing silence to include in the segmentation. **Also see these related items:** [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample) ### include-leading-silence - configuration - int - read-write **C/C++** ```c #define SNSR_INCLUDE_LEADING_SILENCE "include-leading-silence" ``` **Java** ```java public class Snsr { public final static String INCLUDE_LEADING_SILENCE = "include-leading-silence"; } ``` Include leading silence in VAD output. Set to `1` to include all audio up to the endpoint in the [<-audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-pcm-out) output stream. Set to `0` to return to the default behavior, which discards leading silence. If this setting is used with a spot-VAD template such as [tpl-spot-vad](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad.md#tpl-spot-vad-type), [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad-lvcsr.md#tpl-spot-vad-lvcsr-type), or [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-opt-spot-vad-lvcsr.md#tpl-opt-spot-vad-lvcsr-type) the leading silence includes the trigger phrase. **Also see these related items:** [include-wake-word-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-wake-word-audio), [<-audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-pcm-out), [pass-through](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#pass-through) ### include-wake-word-audio - configuration - int - read-write - since [7.6.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.6.0) **C/C++** ```c #define SNSR_INCLUDE_WAKE_WORD_AUDIO "include-wake-word-audio" ``` **Java** ```java public class Snsr { public final static String INCLUDE_WAKE_WORD_AUDIO = "include-wake-word-audio"; } ``` Include the wake word audio in VAD output When set to `1`, VAD templates [tpl-spot-vad](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad.md#tpl-spot-vad-type), [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad-lvcsr.md#tpl-spot-vad-lvcsr-type), and [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-opt-spot-vad-lvcsr.md#tpl-opt-spot-vad-lvcsr-type) include the wake word in the audio output. Set to `0` to return to the default behavior, where the output does not include the wake word audio. **Note:** This setting is a synonym for [include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence) when used with these templates. If you set both `include-wake-word-audio` and `include-leading-silence`, `include-wake-word-audio` takes precedence. **Also see these related items:** [include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence), [<-audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-pcm-out), [pass-through](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#pass-through) ### leading-silence - configuration - int - read-write **C/C++** ```c #define SNSR_LEADING_SILENCE "leading-silence" ``` **Java** ```java public class Snsr { public final static String LEADING_SILENCE = "leading-silence"; } ``` VAD leading silence time-out, in ms. The VAD will invoke the [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence) event handler if no speech is detected during the first `leading-silence` ms of processed audio. **Also see these related items:** [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence), [trailing-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#trailing-silence) ### max-recording - configuration - int - read-write **C/C++** ```c #define SNSR_MAX_RECORDING "max-recording" ``` **Java** ```java public class Snsr { public final static String MAX_RECORDING = "max-recording"; } ``` VAD maximum record duration, in ms. The VAD will invoke the [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit) event handler if the detected speech segment exceeds this value. **Also see these related items:** [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit) ### pass-through - configuration - int - read-write **C/C++** ```c #define SNSR_PASS_THROUGH "pass-through" ``` **Java** ```java public class Snsr { public final static String PASS_THROUGH = "pass-through"; } ``` VAD audio pass-through behavior. If set to `0`, no audio from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm) will be passed through to [<-audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-pcm-out). The begin- and endpoint handlers will still be invoked. The default value, `1`, passes speech-detected samples to [<-audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-pcm-out). **Also see these related items:** [include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence) ### trailing-silence - configuration - int - read-write **C/C++** ```c #define SNSR_TRAILING_SILENCE "trailing-silence" ``` **Java** ```java public class Snsr { public final static String TRAILING_SILENCE = "trailing-silence"; } ``` VAD trailing silence time-out, in ms. The VAD will invoke the [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end) event handler once `trailing-silence` ms of silence has followed the last bit of speech. **Also see these related items:** [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end), [hold-over](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#hold-over), [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence) ## Wake word & command set ### delay - configuration - int - read-only - deprecated [6.16.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.16.0) **C/C++** ```c #define SNSR_SPOT_DELAY "delay" ``` **Java** ```java public class Snsr { public final static String SPOT_DELAY = "delay"; } ``` Phrase spotter delay in ms. **Deprecated:** Support for this setting will be removed from the next major release of the TrulyNatural SDK. First deprecated in release 6.16.0 (2021-06-06) and made read-only in 7.0.0 (2023-11-20). The cumulative recognition score for a wake word or command recognizer can exceed the decision threshold before the end of the utterance. This setting controls how long the recognizer will wait while the recognition score is still increasing before reporting the event. Longer delays can increase the time alignment accuracy of the end of the spotted phrase. ### duration-ms - configuration - double - read-write **C/C++** ```c #define SNSR_DURATION_MS "duration-ms" ``` **Java** ```java public class Snsr { public final static String DURATION_MS = "duration-ms"; } ``` Low false-reject listening window. Selects the time window in ms following a close false-reject that smart wake words will use [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point) instead of [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point). Defaults to `10` seconds if not explicitly set. **Also see these related items:** [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point), [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) ### listen-window - configuration - int - read-write **C/C++** ```c #define SNSR_LISTEN_WINDOW "listen-window" ``` **Java** ```java public class Snsr { public final static String LISTEN_WINDOW = "listen-window"; } ``` Phrase spot listening window in seconds or milliseconds. This is the duration that a spotter will listen for a command before timing out. Spotters with short listening windows are typically optimized to have lower false reject, but higher false accept rates. If this value is `120` or less it is in seconds. Values larger than `120` are in ms. In wake word spotters tuned for continuous listening this value is `0`. **Note:** type: note This value is only used when: * Converting models to DSP format for embedded use. * When the spotter is used in slot `1` of the [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-sequential.md#tpl-spot-sequential-type) spotter template model. In all other cases spotters listen continuously, regardless of the value of `listen-window`. **Also see these related items:** [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-sequential.md#tpl-spot-sequential-type), [loop](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#loop), [What is a Command Set?](https://doc.sensory.com/tnl/7.8/faq.md#use-command-set) ### low-fr-operating-point - configuration - int - read-write **C/C++** ```c #define SNSR_LOW_FR_OPERATING_POINT "low-fr-operating-point" ``` **Java** ```java public class Snsr { public final static String LOW_FR_OPERATING_POINT = "low-fr-operating-point"; } ``` Low false-reject spotter operating point. Selects the low false-reject fall-back operating point used by smart wake words. This low false-reject operating point is selected for [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms) if a spot was rejected at [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) but would have been accepted at `low-fr-operating-point`. **Also see these related items:** [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms), [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) ### operating-point - configuration - int - read-write **C/C++** ```c #define SNSR_OPERATING_POINT "operating-point" ``` **Java** ```java public class Snsr { public final static String OPERATING_POINT = "operating-point"; } ``` Spotter operating point. Selects the trade-off between false accept and false reject errors for wake word and command set recognizers. **Higher-numbered points are more accepting.** * The valid range is from `1` to `21` inclusive. * Lower-numbered points have a lower false accept rate at the expense of higher false reject fraction. * The false accept rate is expressed as the expected number of false accepts (where the recognizer mistakenly spots the trigger phrase) per time unit. For example, 1.2 false accepts per day. * The false reject rate is the percentage of times the actual trigger phrase is spoken, but not recognized. For example, 4.5%. * The default operating point is selected by Sensory during trigger development for a good balance between the these two error types. * Not all operating points are necessarily valid. Use [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator) to find all the [available points](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#available-point). **Also see these related items:** [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator), [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point), [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms) ### score-offset - configuration - double - read-write **C/C++** ```c #define SNSR_SCORE_OFFSET "score-offset" ``` **Java** ```java public class Snsr { public final static String SCORE_OFFSET = "score-offset"; } ``` **Reserved:** Do not use unless recommended by Sensory. ### sv-threshold - configuration - double - read-write **C/C++** ```c #define SNSR_SV_THRESHOLD "sv-threshold" ``` **Java** ```java public class Snsr { public final static String SV_THRESHOLD = "sv-threshold"; } ``` Enrolled wake word speaker verification threshold. Enrolled wake word results with a [sv-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sv-score) less than this threshold are not reported. Increase this threshold to reduce the chance that someone other than the enrolled speaker triggers the phrase spotter. **Also see these related items:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [sv-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sv-score) ### threshold - configuration - int - read-write - deprecated [7.4.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.4.0) **C/C++** ```c #define SNSR_THRESHOLD "threshold" ``` **Java** ```java public class Snsr { public final static String THRESHOLD = "threshold"; } ``` Dynamic operating point selection threshold. **Deprecated:** Superseded by built-in support for smart wake words in TrulyNatural 7.4.0. Selects the threshold used by `tpl-spot-dynop-1.4.0.snsr` to decide whether to select the [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point). **Also see these related items:** [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms), [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point), [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) ## LVCSR & STT ### ac-prune-top-k - configuration - int - read-write _(tnl)_ _(since [7.5.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.5.0))_ **C/C++** ```c #define SNSR_AC_PRUNE_TOP_K "ac-prune-top-k" ``` **Java** ```java public class Snsr { public final static String AC_PRUNE_TOP_K = "ac-prune-top-k"; } ``` Reduce LVCSR decoder CPU use This setting trades CPU use for recognition accuracy. A subset recognizers optimized for low resource use created by [VoiceHub](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub) allow reducing the CPU cycles used in search decoding at the expense of an increased recognition error rate. Set to `0` to disable. ### am-size - configuration - double - read-only - stt **C/C++** ```c #define SNSR_RES_AM_SIZE "am-size" ``` **Java** ```java public class Snsr { public final static String RES_AM_SIZE = "am-size"; } ``` Size of STT acoustic model, in bytes. **Note:** Not supported for all STT models. **Also see these related items:** [lm-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#lm-size), [nlu-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-size), [slm-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-size) ### backlog-interval - configuration - double - read-write _(tnl)_ _(stt)_ _(since [7.7.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.7.0))_ **C/C++** ```c #define SNSR_BACKLOG_INTERVAL "backlog-interval" ``` **Java** ```java public class Snsr { public final static String BACKLOG_INTERVAL = "backlog-interval"; } ``` Partial result update interval used while processing an audio backlog. This setting overrides [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval) when recognizing audio that precedes a wake word, enabled by setting [wake-word-at-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#wake-word-at-end) to `1` or `2`. By default `backlog-interval = 0` for the lowest recognition result latency. **Also see these related items:** [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval), [wake-word-at-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#wake-word-at-end), [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-opt-spot-vad-lvcsr.md#tpl-opt-spot-vad-lvcsr-type), [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad-lvcsr.md#tpl-spot-vad-lvcsr-type) ### complete-only - configuration - int - read-write - tnl **C/C++** ```c #define SNSR_COMPLETE_ONLY "complete-only" ``` **Java** ```java public class Snsr { public final static String COMPLETE_ONLY = "complete-only"; } ``` Controls whether incomplete LVCSR results are accepted. The [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) result available in the [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) callback for LVCSR recognizers reports the recognition result that best matches the acoustic evidence the recognizer saw. With `complete-only = 0` the behavior is to show incomplete results, even if they are not accepted by the grammar specification. For example, if a custom recognizer uses ``` grammar = 1 2 3 4 5 6 7 8 9 10 ; ``` and the audio contains only "1 2 3 4", then the final result will be "1 2 3 4". If this behavior is not desirable, setting `complete-only = 1` will suppress such incomplete results. The [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) callback will still happen, but [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) will be ``. The [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent) and [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) events will not be invoked. _(since [6.20.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.20.0))_ If `complete-only` isn't explicitly set it defaults to `1`. **Also see these related items:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) ### custom-vocab - configuration - string - read-write - stt **C/C++** ```c #define SNSR_CUSTOM_VOCAB "custom-vocab" ``` **Java** ```java public class Snsr { public final static String CUSTOM_VOCAB = "custom-vocab"; } ``` Custom STT vocabulary. STT recognizers occasionally do not have full vocabulary coverage for low-frequency words, proper names, trade marks, and such. Use this custom vocabulary setting to add new words to a recognizer. **Note:** Use custom vocabulary to address minor recognition issues. For more than a couple of hundred entries you'll get better performance with a domain-specific STT model. Please contact your Sensory sales representative to explore options. Map format: ``` output word or phrase [, incorrect result [, incorrect result [, ...]]] ... ``` * New vocabulary word or phrase, * followed by zero or more mis-recognized examples, each prefixed with a `,` separator. * Vocabulary entries are separated by `\r`, `\n` or `;` **Example custom vocabulary:** **`custom-vocab.txt`** ```sh voice genie #(1)! voice genie, voice jenny #(2)! armadillo, i'm adello, amadello #(3)! ``` 1. New vocabulary phrase, without any mis-recognized alternates. If "voice genie" is one of the alternates the recognizer is considering this will increase the likelihood that it is selected as the result. 2. If the STT engine were to recognize "voice jenny" it will be rewritten to "voice genie" 3. If the STT engine recognizes "i'm adello" or "amadello" these will both be rewritten as "armadillo" in the result. **Example:** ```console % snsr-eval -t model/stt-enUS-automotive-medium-2.3.15-pnc.snsr \ -s partial-result-interval=0 \ data/enrollments/armadillo-1-4-c.wav NLU intent: no_command = an anlla record a video 400 1720 an anlla record a video % snsr-eval -t model/stt-enUS-automotive-medium-2.3.15-pnc.snsr \ -s partial-result-interval=0 \ -s 'custom-vocab="armadillo, an anlla; jackalope"' \ data/enrollments/armadillo-1-4-c.wav NLU intent: no_command = armadillo record a video 400 1720 armadillo record a video ``` ### lm-size - configuration - double - read-only - stt **C/C++** ```c #define SNSR_RES_LM_SIZE "lm-size" ``` **Java** ```java public class Snsr { public final static String RES_LM_SIZE = "lm-size"; } ``` Size of STT language model, in bytes. **Note:** Not supported for all STT models. **Also see these related items:** [am-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#am-size), [nlu-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-size), [slm-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-size) ### partial-result-interval - configuration - double - read-write _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_PARTIAL_RESULT_INTERVAL "partial-result-interval" ``` **Java** ```java public class Snsr { public final static String PARTIAL_RESULT_INTERVAL = "partial-result-interval"; } ``` Partial result update interval. The current preliminary result is emitted every `partial-result-interval` milliseconds. Set to `0` to disable partial result reporting. **Warning:** Do not change `partial-result-interval` from an event handler, or while a model is running. **Note:** In STT models this also sets the interval at which the model is evaluated. Less frequent updates trade preliminary result latency for lower average CPU use. Set to `0` for the lowest possible evaluation rate and CPU use. **Also see these related items:** [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) ### ram-limit - configuration - double - read-write _(tnl)_ _(since [7.5.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.5.0))_ **C/C++** ```c #define SNSR_RAM_LIMIT "ram-limit" ``` **Java** ```java public class Snsr { public final static String RAM_LIMIT = "ram-limit"; } ``` Limit LVCSR decoder memory use The amount of heap RAM to allocate to LVCSR search decoding, in bytes. A subset recognizers optimized for low resource use created by [VoiceHub](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub) allow limiting the amount of heap RAM to allocate to search decoding. This setting modifies this limit. Lower values can increase error rates, so we recommend that you set this to as large a value as constraints allow. Set to `0` to disable the limit. **Also see these related items:** [ac-prune-top-k](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#ac-prune-top-k) ### result-max - configuration - int - read-write - tnl **C/C++** ```c #define SNSR_RESULT_MAX "result-max" ``` **Java** ```java public class Snsr { public final static String RESULT_MAX = "result-max"; } ``` The maximum number of alternate phrase results to consider Limits the number of alternate phrases returned by LVCSR models. If `result-max > 1`, [phrase-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phrase-iterator) will return phrase-level recognition results in order of likelihood. The default is `result-max == 1`, which returns only the most likely result. Limitations - [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) and [phone-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phone-iterator) are available for the most likely result only. - Time alignments are accurate for the most likely result only. - [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score) values are not usable when `result-max > 1`. - Silence markup is elided from all but the top scoring phrase. An empty [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) result indicates that silence was the best match to the acoustic input. **Warning:** N-best processing is computationally expensive, frequently prohibitively so. Contact Sensory for guidance before using this feature in production. **Also see these related items:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [phrase-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phrase-iterator) ### search.frame-nota - configuration - double - read-write - tnl **C/C++** ```c #define SNSR_OOV_REJECT "search.frame-nota" ``` **Java** ```java public class Snsr { public final static String OOV_REJECT = "search.frame-nota"; } ``` Out-of-vocabulary rejection sensitivity. This setting controls out-of-vocabulary rejection in custom LVCSR recognizers. Custom LVCSR recognizers report `` for words or phrases that are not in the grammar. With an `search.frame-nota` value of `0` the recognizer will never report ``, it will return the closest match instead. With `search.frame-nota` at `1.0`, almost all input will return ``. The optimal value for `search.frame-nota` depends on the vocabulary used. A reasonable value to start testing with is `0.2`. **Note:** Do not change `search.frame-nota` for models that include statistical language model components. These models typically have either `-broad-` or `-background-` in the model name, and are configured to use the language model to recognize utterances not covered by the custom grammar. **Also see these related items:** [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream) ### show-silence - configuration - int - read-write - tnl **C/C++** ```c #define SNSR_SHOW_SILENCE "show-silence" ``` **Java** ```java public class Snsr { public final static String SHOW_SILENCE = "show-silence"; } ``` Include silence in recognizer results. When set to `1`, LVCSR recognition results include word-pause ``, sentence-begin ``, and sentence-end `` markup. The default value is `0`, which elides these from results. **Also see these related items:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) ### stt-profile - configuration - string - read-write _(stt)_ _(since [7.4.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.4.0))_ **C/C++** ```c #define SNSR_STT_PROFILE "stt-profile" ``` **Java** ```java public class Snsr { public final static String STT_PROFILE = "stt-profile"; } ``` Select STT speed vs accuracy trade-off. Default value is `accurate`, set to `fast` to reduce CPU load at the expense of recognition accuracy. **Also see these related items:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) ## NLU & SLM ### nlu-match-max - configuration - int - read-write - tnl **C/C++** ```c #define SNSR_NLU_RES_MAX "nlu-match-max" ``` **Java** ```java public class Snsr { public final static String NLU_RES_MAX = "nlu-match-max"; } ``` The maximum number of alternate NLU matches to consider Limits the number of [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) callbacks issued in case of multiple valid NLU matches to the recognition result. The default value is `1`, limiting NLU results to the best-scoring match only. **Also see these related items:** [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot), [nlu-match-index](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-match-index), [nlu-slot-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-count) ### nlu-size - configuration - double - read-only - stt **C/C++** ```c #define SNSR_RES_NLU_SIZE "nlu-size" ``` **Java** ```java public class Snsr { public final static String RES_NLU_SIZE = "nlu-size"; } ``` Size of STT NLU model, in bytes. **Note:** Not supported for all STT models. **Also see these related items:** [am-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#am-size), [lm-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#lm-size), [slm-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-size) ### slm-enabled - configuration - int - read-write _(stt)_ _(since [7.4.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.4.0))_ **C/C++** ```c #define SNSR_SLM_ENABLED "slm-enabled" ``` **Java** ```java public class Snsr { public final static String SLM_ENABLED = "slm-enabled"; } ``` Enable optional SLM component. Set to `0` to turn the SLM component off, `1` to turn on. **Also see these related items:** [^slm-start](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-start), [^slm-result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result), [^slm-result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result-partial), [slm-turn-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-turn-limit) ### slm-size - configuration - double - read-only _(stt)_ _(since [7.5.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.5.0))_ **C/C++** ```c #define SNSR_RES_SLM_SIZE "slm-size" ``` **Java** ```java public class Snsr { public final static String RES_SLM_SIZE = "slm-size"; } ``` Size of STT SLM, in bytes. **Note:** Not supported for all STT models. **Also see these related items:** [am-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#am-size), [lm-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#lm-size), [nlu-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-size) ### slm-turn-limit - configuration - int - read-write _(stt)_ _(since [7.4.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.4.0))_ **C/C++** ```c #define SNSR_SLM_TURN_LIMIT "slm-turn-limit" ``` **Java** ```java public class Snsr { public final static String SLM_TURN_LIMIT = "slm-turn-limit"; } ``` Configure SLM history behavior. If `slm-turn-limit >= 0` the optional SLM component limits the number of conversational turns in the model history. The default `-1`, which keeps all history. Writing to `slm-turn-limit` discards existing history. **Note:** Values larger than `0` increases the SLM result latency and CPU use. **Also see these related items:** [^slm-result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result), [^slm-result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result-partial), [slm-enabled](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-enabled) ## Templates & slots ### 0. - configuration - stream - read-write **C/C++** ```c #define SNSR_SLOT_0 "0." ``` **Java** ```java public class Snsr { public final static String SLOT_0 = "0."; } ``` Template slot `0`. The first slot in a template task. Template slots expect a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) opened on a `.snsr` model file. You can also use this string value as an argument with [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot). **Also see these related items:** [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot) ### 1. - configuration - stream - read-write **C/C++** ```c #define SNSR_SLOT_1 "1." ``` **Java** ```java public class Snsr { public final static String SLOT_1 = "1."; } ``` Template slot `1`. The second slot in a template task. Template slots expect a [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) opened on a `.snsr` model file. You can also use this string value as an argument with [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot). **Also see these related items:** [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot) ### include-model - configuration - int - read-write **C/C++** ```c #define SNSR_INCLUDE_MODEL "include-model" ``` **Java** ```java public class Snsr { public final static String INCLUDE_MODEL = "include-model"; } ``` Debug log includes a copy of the model. This boolean value controls whether the [debug-log-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#debug-log-file) includes a copy of the task model (the `.snsr` file). The default value is `1`. Set `include-model=0` for smaller (but less complete) debug log files. **Also see these related items:** [debug-log-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#debug-log-file) ### loop - configuration - int - read-write **C/C++** ```c #define SNSR_LOOP "loop" ``` **Java** ```java public class Snsr { public final static String LOOP = "loop"; } ``` Control template looping behavior. In [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-sequential.md#tpl-spot-sequential-type), setting this value to `1` changes _when_ the listening focus returns to slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0). Instead of immediately returning to slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0) after a spot in slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1), it resets the expiration timer, and only a [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1).[listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window) timeout returns to slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0). This allows for a wake word followed by zero or more commands from a command set. The default behavior (`loop = 0`) is to allow at most one command before requiring another wake word utterance. _(since [7.6.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.6.0))_ Setting `loop = 2` pins the listening focus to slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1). Use this, for example, if an application needs to gate a command set recognizer with a wake word or an external event such as a push-to-talk button. **Also see these related items:** [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-sequential.md#tpl-spot-sequential-type), [listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window) ### slot - configuration - string - read-write **C/C++** ```c #define SNSR_SLOT "slot" ``` **Java** ```java public class Snsr { public final static String SLOT = "slot"; } ``` Template slot selector. Use with [tpl-spot-select](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-select.md#tpl-spot-select-type) and [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-opt-spot-vad-lvcsr.md#tpl-opt-spot-vad-lvcsr-type) to select the active slot. **Also see these related items:** [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0), [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1), [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot), [lvcsr](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#lvcsr) ### wake-word-at-end - configuration - int - read-write - since [7.7.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.7.0) **C/C++** ```c #define SNSR_WAKE_WORD_AT_END "wake-word-at-end" ``` **Java** ```java public class Snsr { public final static String WAKE_WORD_AT_END = "wake-word-at-end"; } ``` Support for trailing wake words. Setting this to `1` or `2` enables support for recognizing utterances gated by a wake word at the end of an utterance, in addition to gating by a wake word at the start. `1` does not include the wake word audio, but `2` does. `0` turns this feature off. **Note:** This feature requires an [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size) large enough to hold the entire utterance. Enabling `wake-word-at-end` will increase this to ten seconds if it starts out smaller. If the utterance before the wake word does not fit into the `audio-stream-size` ring buffer, the VAD will invoke the [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit) event instead of [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end) **Also see these related items:** [backlog-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backlog-interval), [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-opt-spot-vad-lvcsr.md#tpl-opt-spot-vad-lvcsr-type), [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad-lvcsr.md#tpl-spot-vad-lvcsr-type), [tpl-spot-vad](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad.md#tpl-spot-vad-type), [use-trailing-wake-word](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-opt-spot-vad-lvcsr.md#use-trailing-wake-word) ## Enrollment & adaptation ### accuracy - configuration - double - read-write **C/C++** ```c #define SNSR_ACCURACY "accuracy" ``` **Java** ```java public class Snsr { public final static String ACCURACY = "accuracy"; } ``` Enrollment accuracy. Trades accuracy of the enrolled model for enrollment speed. The default accuracy is `1.0`, for the best accuracy at the slowest enrollment speed. Valid range is `0.0` to `1.0`. **Also see these related items:** [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), [^enrolled](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#enrolled) ### ctx-enroll - configuration - int - read-write **C/C++** ```c #define SNSR_ENROLLMENT_CONTEXT "ctx-enroll" ``` **Java** ```java public class Snsr { public final static String ENROLLMENT_CONTEXT = "ctx-enroll"; } ``` Number of enrollments with trailing context. The recommended number of enrollments where the phrase is followed by additional speech. For example: "Hey Sensory will it rain tomorrow?" ### enrollment-task-index - configuration - int - read-write **C/C++** ```c #define SNSR_ENROLLMENT_TASK_INDEX "enrollment-task-index" ``` **Java** ```java public class Snsr { public final static String ENROLLMENT_TASK_INDEX = "enrollment-task-index"; } ``` The index of the sub-task to enroll. For enrollment tasks that contain multiple sub-tasks (for example, a user-defined trigger and an enrolled fixed trigger), this integer value selects which of the sub-tasks the enrollments should be applied to. See the documentation delivered with the task file for the sub-task mapping. **Note:** For most enrollment tasks the only supported task index is `0`. ### interactive - configuration - int - read-write **C/C++** ```c #define SNSR_INTERACTIVE_MODE "interactive" ``` **Java** ```java public class Snsr { public final static String INTERACTIVE_MODE = "interactive"; } ``` Interactive enrollment mode. This changes the enrollment task behavior: When set to `0`, enrollment for the current phrase will continue until the end of the stream. **Also see these related items:** [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), [^enrolled](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#enrolled) ### max-users - configuration - int - read-write **C/C++** ```c #define SNSR_MAX_USERS "max-users" ``` **Java** ```java public class Snsr { public final static String MAX_USERS = "max-users"; } ``` Maximum number of users to adapt to. Sets a limit to the number of distinct users a continuously adapting fixed-phrase spotter will enroll. ### req-enroll - configuration - int - read-write **C/C++** ```c #define SNSR_ENROLLMENT_TARGET "req-enroll" ``` **Java** ```java public class Snsr { public final static String ENROLLMENT_TARGET = "req-enroll"; } ``` Enrollment target. The recommended number of enrollments for each user. Using either more or fewer enrollments will reduce overall spotter performance. **Also see these related items:** [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator), [enrollment-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#enrollment-count) ### save-enroll-audio - configuration - int - read-write **C/C++** ```c #define SNSR_SAVE_ENROLLMENT_AUDIO "save-enroll-audio" ``` **Java** ```java public class Snsr { public final static String SAVE_ENROLLMENT_AUDIO = "save-enroll-audio"; } ``` Include enrollment audio in the enrollment context. Set to `1` to include the enrollment audio in enrollment contexts, `0` to exclude. **Also see these related items:** [RUNTIME](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_runtime), [enrollment-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#enrollment-iterator) ### user - configuration - string - read-write **C/C++** ```c #define SNSR_USER "user" ``` **Java** ```java public class Snsr { public final static String USER = "user"; } ``` Enrolling user tag. Sets the tag for the current enrollment. This should be a unique alphanumeric phrase, without spaces. It is the phrase returned as a recognition result. If enrolling more than one phrase for any of the users, the tag *must* contain one `/` that separates a user-specific part from the phrase part. For example: `user1/phrase1`, `user2/phrase1`, `user2/phrase2`. **Also see these related items:** [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), [^enrolled](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#enrolled) ## Push / pull execution ### push-buffer-backlog - configuration - int - read-write **C/C++** ```c #define SNSR_RES_PUSH_BUFFER_BACKLOG "push-buffer-backlog" ``` **Java** ```java public class Snsr { public final static String RES_PUSH_BUFFER_BACKLOG = "push-buffer-backlog"; } ``` Reports the number of bytes of deferred [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) data. If [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) is used with a [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit), this setting reports the number of bytes deferred for processing in subsequent calls to [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push). **Also see these related items:** [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), [push-buffer-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-buffer-size), [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit) ### push-buffer-size - configuration - int - read-write **C/C++** ```c #define SNSR_PUSH_BUFFER_SIZE "push-buffer-size" ``` **Java** ```java public class Snsr { public final static String PUSH_BUFFER_SIZE = "push-buffer-size"; } ``` The size of the internal ring buffers used by [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push). If [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) is used with a [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit), processing will require deferral if the duration limit is reached. In this case, [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) will allocate a ring buffer to hold these data. This setting configures the size of this buffer, in bytes. The default buffer size is sufficient to defer up to 250 ms of audio data. **Also see these related items:** [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit), [push-buffer-backlog](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-buffer-backlog) ### push-duration-limit - configuration - double - read-write **C/C++** ```c #define SNSR_PUSH_DURATION_LIMIT "push-duration-limit" ``` **Java** ```java public class Snsr { public final static String PUSH_DURATION_LIMIT = "push-duration-limit"; } ``` Sets a limit to the maximum processing time [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) should consume. This setting is the maximum number of milliseconds any call to [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) should spend processing data before returning control to the caller. The default value is `0`, which disables the processing limit. **Note:** This requires a valid real-time clock function, see [CONFIG_CLOCK_FUNC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_clock_func). TrulyNatural SDK libraries for Android, Linux, macOS, iOS, and Java include real-time clock functions and require no additional configuration. You should use a `push-duration-limit` if: * You're using [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), and * you collect live audio on the same thread as the recognizer, and * you will drop audio packets if you don't return from [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) before the next packet is available. `push-duration-limit` adds a cap to the amount of CPU used in each call to [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push). This requires and allocates an additional input ring buffer that's [push-buffer-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-buffer-size) bytes in size. If you have a separate thread, or interrupt-driven live audio recording and you want to maximize throughput, increase the size of the audio ring buffer instead of using a `push-duration-limit`. Recommendations: * Use 15 ms audio chunks. * The audio recording buffer size determines the longest time the average recognizer throughput can fall behind real time. * With a 30 ms buffer only two 15 ms blocks fit, which means that every SDK processing call must return within 15 ms, or we'll lose a block or partial block. * Using a 300 ms buffer relaxes this. 20 blocks mean that we can fall up to 18 blocks (270 ms) behind before losing audio. **Also see these related items:** [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), [push-buffer-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-buffer-size), [push-buffer-backlog](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-buffer-backlog), [CLOCK_FUNC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_clock_func) ## Logging & diagnostics ### cache-file - configuration - string - read-write **C/C++** ```c #define SNSR_CACHE_FILE "cache-file" ``` **Java** ```java public class Snsr { public final static String CACHE_FILE = "cache-file"; } ``` Continuous Adaptation cache file name. When set, enrolled user data will be saved to, and loaded from this file. If not set, enrolled user data are discarded when the spotter session is released. This setting is only available in fixed-phrase spotters that support continuous adaptation. If you need more control over how or when the enrollment context is saved you can do this from the [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted) callback handler. **Also see these related items:** [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted) ### debug-log-file - configuration - string - read-write **C/C++** ```c #define SNSR_DEBUG_LOG_FILE "debug-log-file" ``` **Java** ```java public class Snsr { public final static String DEBUG_LOG_FILE = "debug-log-file"; } ``` Debug log filename. The name of the log file [tpl-spot-debug](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-debug.md#tpl-spot-debug-type) writes to. This value is required, and no default is defined in the template. The directory the log file is in must exist, and must be writable. These optional and mutually exclusive character sequences are substituted with the time stamp when the log file is first opened: * `%@` - year-month-day_hour-minute-second.milliseconds (UTC) * `%#` - milliseconds since the [epoch][]. **Example:** **C/C++** ```c snsrSetString(session, SNSR_DEBUG_LOG_FILE, "debug-%#.log"); ``` **Java** ```java session.setString(Snsr.DEBUG_LOG_FILE, "debug-%#.log"); ``` ### fex-hash - configuration - string - read-only - pre-release **C/C++** ```c #define SNSR_FEATURE_HASH "fex-hash" ``` **Java** ```java public class Snsr { public final static String FEATURE_HASH = "fex-hash"; } ``` Feature extractor hash. **Pre-release:** This is an experimental feature. Do not use unless recommended by Sensory. This is a unique string that identifies the feature type used by the task. ## Identity & metadata ### task-name - configuration - string - read-only - deprecated [6.14.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.14.0) **C/C++** ```c #define SNSR_TASK_NAME "task-name" ``` **Java** ```java public class Snsr { public final static String TASK_NAME = "task-name"; } ``` Task name. **Deprecated:** Support for this setting will be removed from the next major release of this SDK. **Do not use this in new code.** ### task-type - configuration - string - read-only **C/C++** ```c #define SNSR_TASK_TYPE "task-type" ``` **Java** ```java public class Snsr { public final static String TASK_TYPE = "task-type"; } ``` Task type. This, together with [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version), describes the model behavior: Which [setting keys](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) and [streams](https://doc.sensory.com/tnl/7.8/api/io.md#stream) it supports. Examples include: [enroll](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#enroll), [lvcsr](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#lvcsr), [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot), [phrasespot-vad](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot-vad), and [vad](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#vad). **Also see these related items:** [Values](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#values), [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version), [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require) ### task-type-and-version-list - configuration - string - write-only **C/C++** ```c #define SNSR_TASK_TYPE_AND_VERSION_LIST "task-type-and-version-list" ``` **Java** ```java public class Snsr { public final static String TASK_TYPE_AND_VERSION_LIST = "task-type-and-version-list"; } ``` Verifies that a model matches one of list of types and versions. When used with [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require), the value argument must be a semicolon-separated list of [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) and [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version) values. This list must have at least one element. A task will match the requirement if one of the [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) fields match, and the corresponding [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version) is satisfied. If no [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) matches, [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require) returns [REQUIRE_MISMATCH](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). If a [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) matches, but the associated [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version) is not satisfied, [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require) returns [VERSION_MISMATCH](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). **Example:** **C/C++** ```c snsrRequire(session, SNSR_TASK_TYPE_AND_VERSION_LIST, SNSR_PHRASESPOT " ~0.5.0 || 1.0.0;" SNSR_LVCSR " 1.0.0"); ``` **Java** ```java session.require(Snsr.TASK_TYPE_AND_VERSION_LIST, Snsr.PHRASESPOT + " ~0.5.0 || 1.0.0;" + Snsr.LVCSR + " 1.0.0"); ``` **Also see these related items:** [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require) ### task-version - configuration - string - read-only **C/C++** ```c #define SNSR_TASK_VERSION "task-version" ``` **Java** ```java public class Snsr { public final static String TASK_VERSION = "task-version"; } ``` Model task version. These version strings follow [semantic versioning](http://semver.org/) rules. **Also see these related items:** [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type), [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require) [epoch]: https://en.wikipedia.org/wiki/Unix_time "Unix time" *[API]: Application Programming Interface *[FR]: False Reject: the recognizer did not trigger when the target phrase was spoken *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[NLU]: Natural Language Understanding model *[RAM]: Random Access Memory *[SDK]: Software Development Kit *[SLM]: Generative Small Language Model *[STT]: Speech To Text: transformers with language model and CTC decoding *[THF]: TrulyHandsfree, Sensory's wake word and command recognition technology *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[VAD]: Voice Activity Detector --- source_path: "api/setting-keys/events.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/setting-keys/events/" --- # Events Use [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) with keys in this section to register callback handlers for events. The values for these settings refer to runtime instances of code objects and are not serialized by [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save) or [dup](https://doc.sensory.com/tnl/7.8/api/inference.md#dup). The [• results](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#results) and [• iterators](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators) available in these handlers vary by event. See the descriptions below for details on what these are. [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) is the most used event by a large margin. ### Details: Page conventions Settings are grouped by concern. Within each group they're listed alphabetically. A setting that serves more than one concern appears once under its primary group; secondary groups link to it. ## Audio I/O ### ^sample-count - event - handle - write-only **C/C++** ```c #define SNSR_SAMPLES_EVENT "^sample-count" ``` **Java** ```java public class Snsr { public final static String SAMPLES_EVENT = "^sample-count"; } ``` Samples available event. Raised whenever audio samples have been read from the input stream and are about to be processed. **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ ## VAD & endpointing ### ^begin - event - handle - write-only **C/C++** ```c #define SNSR_BEGIN_EVENT "^begin" ``` **Java** ```java public class Snsr { public final static String BEGIN_EVENT = "^begin"; } ``` Begin point detected VAD event. Raised when speech has been detected. Use [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms) or [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample) to retrieve the start point relative to the beginning of [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm). **Available results:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [backoff](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backoff), [end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end), [limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit), [silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence) ### ^end - event - handle - write-only **C/C++** ```c #define SNSR_END_EVENT "^end" ``` **Java** ```java public class Snsr { public final static String END_EVENT = "^end"; } ``` Endpoint detected VAD event. Raised [trailing-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#trailing-silence) ms after end-of-speech has been detected. Use [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms) or [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample) to retrieve the endpoint relative to the beginning of [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm). **Available results:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample), [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin), [limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit), [silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence), [hold-over](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#hold-over), [trailing-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#trailing-silence) ### ^limit - event - handle - write-only **C/C++** ```c #define SNSR_LIMIT_EVENT "^limit" ``` **Java** ```java public class Snsr { public final static String LIMIT_EVENT = "^limit"; } ``` Maximum recording reached VAD event. Raised when [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording) ms of speech has been processed by the VAD before a trailing-silence endpoint is found. Use [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms) or [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample) to retrieve the endpoint relative to the beginning of [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm). **Available results:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample), [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin), [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end), [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence), [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording) ### ^silence - event - handle - write-only **C/C++** ```c #define SNSR_SILENCE_EVENT "^silence" ``` **Java** ```java public class Snsr { public final static String SILENCE_EVENT = "^silence"; } ``` No speech detected event. Raised if no speech is detected within [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence) ms from the start of [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), adjusted by [skip-to-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#skip-to-ms) or [skip-to-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#skip-to-sample) **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence), [skip-to-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#skip-to-ms), [skip-to-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#skip-to-sample) ## Wake word & command set ### ^result - event - handle - write-only **C/C++** ```c #define SNSR_RESULT_EVENT "^result" ``` **Java** ```java public class Snsr { public final static String RESULT_EVENT = "^result"; } ``` Recognition result available event. Raised when a final recognition hypothesis is available. **Available results:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [confidence-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#confidence-score), [domain](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#domain), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample), [id](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#id), [noise-energy](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#noise-energy), [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score), [signal-energy](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#signal-energy), [snr](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#snr), [sv-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sv-score), [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) **Available iterators:** [phone-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phone-iterator), [phrase-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phrase-iterator), [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count), [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) **Also see these related items:** [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) ## Templates & slots ### ^listen-begin - event - handle - write-only **C/C++** ```c #define SNSR_LISTEN_BEGIN_EVENT "^listen-begin" ``` **Java** ```java public class Snsr { public final static String LISTEN_BEGIN_EVENT = "^listen-begin"; } ``` Sequential task has started listening on second slot. Raised in a sequential task when audio focus has shifted from the first slot to the second. This typically happens when the spotter n the first slot has detected the phrase. This event is ignored for tasks that do not feature sequential behavior. **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [^listen-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-end) ### ^listen-end - event - handle - write-only **C/C++** ```c #define SNSR_LISTEN_END_EVENT "^listen-end" ``` **Java** ```java public class Snsr { public final static String LISTEN_END_EVENT = "^listen-end"; } ``` Sequential task has stopped listening on second slot. Raised in a sequential task when audio focus has shifted from the second slot back to the first. This event is ignored for tasks that do not feature sequential behavior. **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [^listen-begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-begin) ## LVCSR & STT ### ^result - event - handle - write-only Documented under **Wake word & command set** ([^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result)). Emitted by every recognizer with a final result. ### ^result-partial - event - handle - write-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_PARTIAL_RESULT_EVENT "^result-partial" ``` **Java** ```java public class Snsr { public final static String PARTIAL_RESULT_EVENT = "^result-partial"; } ``` Partial recognition result available event. Raised when a preliminary recognition hypothesis is available. **Available results:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [domain](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#domain), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample), [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count), [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score), [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) **Available iterators:** [phone-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phone-iterator), [phrase-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phrase-iterator), [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) **Also see these related items:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) ## NLU & SLM ### ^nlu-intent - event - handle - write-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_NLU_INTENT_EVENT "^nlu-intent" ``` **Java** ```java public class Snsr { public final static String NLU_INTENT_EVENT = "^nlu-intent"; } ``` NLU intent available. This event is raised when a natural language parse result is available. Each intent that matched input generates an `^nlu-intent` event. Use [nlu-entity-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-entity-iterator) in this callback handler to retrieve the names of entities found. An intent is an action, such as turning on the windshield wipers, or setting a microwave clock. Intents are exactly the same as the top-level NLU slots reported by [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot). The entities available inside the handler for this event, however, are only one level deep. The SDK flattens nested [nlu-slot-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-name)s by separating each level with a period. For example: Grammar snippet `{ date { time {hours} {minutes} } }` has intent `date` with entities `time.hours` and `time.minutes`, but slot `date` has a single child slot `time`, which in turn has two children, `hours` and `minutes`. See the [NLU section](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#nlu-markup) in the [grammar syntax](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-syntax) section for more detail on the `{}` NLU slot capturing operator. **Available results:** [nlu-intent-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-name), [nlu-intent-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-score), [nlu-intent-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-value), [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** [nlu-entity-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-entity-iterator) **Also see these related items:** [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot), [grammar syntax](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-syntax) ### ^nlu-slot - event - handle - write-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_NLU_SLOT_EVENT "^nlu-slot" ``` **Java** ```java public class Snsr { public final static String NLU_SLOT_EVENT = "^nlu-slot"; } ``` NLU result available. This event is raised when a lightweight natural language parse result is available. Each top-level slot that matched input generates a `^nlu-slot` event. Use [nlu-slot-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-slot-iterator) in this callback handler to retrieve child slot names and values. See the [NLU section](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#nlu-markup) in the [grammar syntax](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-syntax) section for more detail on the `{}` NLU slot capturing operator. **Available results:** [nlu-match-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-match-count), [nlu-slot-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-count), [nlu-slot-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-name), [nlu-slot-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-score), [nlu-slot-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-value), [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** [nlu-slot-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-slot-iterator) **Also see these related items:** [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent), [grammar syntax](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-syntax) ### ^slm-result - event - handle - write-only _(stt)_ _(since [7.4.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.4.0))_ **C/C++** ```c #define SNSR_SLM_RESULT_EVENT "^slm-result" ``` **Java** ```java public class Snsr { public final static String SLM_RESULT_EVENT = "^slm-result"; } ``` SLM final output available This event is raised when an optional SLM has a complete result available. In the handler for this callback [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) holds the entire SLM response. **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count), [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) **Available iterators:** _none_ **Also see these related items:** [^slm-result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result-partial) ### ^slm-result-partial - event - handle - write-only _(stt)_ _(since [7.4.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.4.0))_ **C/C++** ```c #define SNSR_SLM_PARTIAL_RESULT_EVENT "^slm-result-partial" ``` **Java** ```java public class Snsr { public final static String SLM_PARTIAL_RESULT_EVENT = "^slm-result-partial"; } ``` SLM partial output available This event is raised when an optional SLM has a new word prediction available. In the handler for this callback [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) holds the next word prediction. Return [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop) from the callback to abort further SLM generation; this will not stop the overall recognition pipeline. **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count), [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) **Available iterators:** _none_ **Also see these related items:** [^slm-result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result) ### ^slm-start - event - handle - write-only _(stt)_ _(since [7.4.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.4.0))_ **C/C++** ```c #define SNSR_SLM_START_EVENT "^slm-start" ``` **Java** ```java public class Snsr { public final static String SLM_START_EVENT = "^slm-start"; } ``` SLM processing is about to start Return [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop) from the callback handler to avoid doing SLM processing. **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [^slm-result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result), [^slm-result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result-partial) ## Enrollment & adaptation ### ^adapt-started - event - handle - write-only **C/C++** ```c #define SNSR_ADAPT_STARTED_EVENT "^adapt-started" ``` **Java** ```java public class Snsr { public final static String ADAPT_STARTED_EVENT = "^adapt-started"; } ``` Wake word model adaptation thread has started. This handler is called from a thread started to do model adaptation in continuously adapting spotter models. The handle function should return [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) to continue with model adaptation, or [SKIP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_skip) to abort adaptation and ignore this enrollment without raising an error. The handler function's [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) argument will be `NULL` as it is not safe to access this handle from the enrollment thread. You can use this handler to adjust the adaptation thread priority, or delay the start of adaptation by blocking on a condition variable. **Note:** [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) teardown waits on joining the adaptation thread. Any handler function registered for this event must return before the associated [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) is released. **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted) ### ^adapted - event - handle - write-only **C/C++** ```c #define SNSR_ADAPTED_EVENT "^adapted" ``` **Java** ```java public class Snsr { public final static String ADAPTED_EVENT = "^adapted"; } ``` Wake word adaptation complete event. Adaptation is the estimation of spotter model parameters from a number of enrollments for one or more users. **Example:** Add a handler for this event to save adapted enrollment contexts. **C/C++** ```c snsrSave(session, SNSR_FM_RUNTIME, snsrStreamFromFileName("context.snsr", "w")); ``` **Java** ```java session.save(Snsr.FM_RUNTIME, SnsrStream.fromFileName("context.snsr", "w")); ``` To load a previously saved enrollment context, do so _after_ loading the model that created it. **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count), [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user), [user-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#user-count) **Available iterators:** [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator) **Also see these related items:** [^enrolled](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#enrolled), [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save), [RUNTIME](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_runtime) ### ^done - event - handle - write-only **C/C++** ```c #define SNSR_DONE_EVENT "^done" ``` **Java** ```java public class Snsr { public final static String DONE_EVENT = "^done"; } ``` Wake word adaptation complete event. Handler called when adaptation has completed and the [model-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#model-stream) model is available. This handler typically returns [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop) to end processing. **Available results:** [model-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#model-stream), [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ ### ^enrolled - event - handle - write-only **C/C++** ```c #define SNSR_ENROLLED_EVENT "^enrolled" ``` **Java** ```java public class Snsr { public final static String ENROLLED_EVENT = "^enrolled"; } ``` Wake word enrollment complete event. Handler called when enrollment is complete, just before model adaptation starts. Use this handler for the earliest possible access to the enrollment context. Enrollment is the process of taking individual enrollments (audio files or live audio clips), validating them, and adding them to the model. These enrollments are used during the adaptation stage to estimate spotter model parameters. **Example:** Add a handler for this event to save enrollment contexts before they are adapted. **C/C++** ```c snsrSave(session, SNSR_FM_RUNTIME, snsrStreamFromFileName("enrollments.snsr", "w")); ``` **Java** ```java session.save(Snsr.FM_RUNTIME, SnsrStream.fromFileName("enrollments.snsr", "w")); ``` **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), [^done](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#done), [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save), [RUNTIME](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_runtime) ### ^fail - event - handle - write-only **C/C++** ```c #define SNSR_FAIL_EVENT "^fail" ``` **Java** ```java public class Snsr { public final static String FAIL_EVENT = "^fail"; } ``` Wake word enrollment failed event. Handler called if an enrollment fails quality checks. **Available results:** [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream), [enrollment-id](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#enrollment-id), [reason](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason), [reason-guidance](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-guidance), [reason-pass](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-pass), [reason-threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-threshold), [reason-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-value), [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** [reason-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#reason-iterator) **Also see these related items:** [^pass](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#pass) ### ^new-user - event - handle - write-only **C/C++** ```c #define SNSR_NEW_USER_EVENT "^new-user" ``` **Java** ```java public class Snsr { public final static String NEW_USER_EVENT = "^new-user"; } ``` New user detected event. Handler called when a continuously adapting spotter model has adapted to a new user. **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count), [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user), [user-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#user-count) **Available iterators:** [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator) **Also see these related items:** [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), [delete-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#delete-user), [rename-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#rename-user), [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) ### ^next - event - handle - write-only **C/C++** ```c #define SNSR_NEXT_EVENT "^next" ``` **Java** ```java public class Snsr { public final static String NEXT_EVENT = "^next"; } ``` Next user event. Handler called during interactive enrollment to prompt the end-user for a new enrollment phrase. This handler should set [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) to the tag associated with the new user. Leave [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) if there are no more users or phrases to enroll. **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) ### ^pass - event - handle - write-only **C/C++** ```c #define SNSR_PASS_EVENT "^pass" ``` **Java** ```java public class Snsr { public final static String PASS_EVENT = "^pass"; } ``` Wake word enrollment succeeded event. Handler called when an enrollment passes quality checks. Return [SKIP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_skip) from this event handler to discard an enrollment. **Available results:** [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream), [audio-stream-first](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-first), [audio-stream-last](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-last), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample), [enrollment-id](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#enrollment-id), [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail) ### ^pause - event - handle - write-only **C/C++** ```c #define SNSR_PAUSE_EVENT "^pause" ``` **Java** ```java public class Snsr { public final static String PAUSE_EVENT = "^pause"; } ``` Input stream pause event. Handler called when a time-consuming processing step is about to start. Use this handler to pause the input stream when doing interactive enrollment. **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [^resume](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#resume) ### ^progress - event - handle - write-only **C/C++** ```c #define SNSR_PROG_EVENT "^progress" ``` **Java** ```java public class Snsr { public final static String PROG_EVENT = "^progress"; } ``` Wake word adaptation progress event. Handler called to report adaptation progress. **Available results:** [percent-done](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#percent-done), [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted) ### ^resume - event - handle - write-only **C/C++** ```c #define SNSR_RESUME_EVENT "^resume" ``` **Java** ```java public class Snsr { public final static String RESUME_EVENT = "^resume"; } ``` Input stream resume event. Handler called when a time-consuming processing step has completed. Use this handler to restart an input stream that was stopped during a [^pause](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#pause) event handler. **Available results:** [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) **Available iterators:** _none_ **Also see these related items:** [^pause](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#pause) *[API]: Application Programming Interface *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[NLU]: Natural Language Understanding model *[SDK]: Software Development Kit *[SLM]: Generative Small Language Model *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[VAD]: Voice Activity Detector --- source_path: "api/setting-keys/index.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/setting-keys/" --- # Setting keys Settings are strings used as keys in [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) object function or method calls. There are different categories of keys, defined by how they are used. [Configuration](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#configuration), [Runtime](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#runtime), [Results](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#results), [Events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events), and [Iterators](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators) are organized by **concern** (for example, **Audio I/O** or **Wake word & command set**). Within each group, entries are listed alphabetically. A setting that applies to more than one concern is documented once under its primary group; other groups link to that entry. [Values](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#values) and [Library information](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-information) are short, flat lists and are not grouped this way. [Events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) - Use [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) with event keys to register callback handlers for events. [Iterators](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators) - Use with [forEach](https://doc.sensory.com/tnl/7.8/api/inference.md#foreach) to loop over lists of values. [Results](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#results) - Report the results of model [inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference). [Runtime](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#runtime) - Inspect or alter the runtime state of [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instances. [Configuration](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#configuration) - Change or fine-tune model behavior. Values for these keys persist in model files. You can modify these settings with the `-s` option in the command-line utilities. [Values](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#values) - String constants that define [task-types](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) used with [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require), or that identify template [slots](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot). [Library information](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-information) - Information about the library, rather than any specific model. **Concern groups (Configuration, Runtime, Results, Events, Iterators):** The same group names appear on every grouped page; a page omits groups that have no entries. Groups used in this reference: - **Audio I/O** — streams and the audio history buffer - **VAD & endpointing** — voice activity detection and silence handling - **Wake word & command set** — operating point, listen window, thresholds - **LVCSR & STT** — decoder tuning, grammar streams, STT vocabulary, transcription profile - **Alignment & timing** — sample/millisecond offsets ([Results](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#results) only) - **NLU & SLM** — intents, entities, and SLM controls - **Templates & slots** — slot identifiers and template loop/include behavior - **Enrollment & adaptation** — enrollment flow and adaptation - **Push / pull execution** — push buffers, duration limits, flush behavior - **THF Micro DSP** — export streams, target port, and conversion results for THF Micro embedded deployments - **Logging & diagnostics** — debug logging and profiling - **Identity & metadata** — task/model identity and licensing *[API]: Application Programming Interface *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[NLU]: Natural Language Understanding model *[SLM]: Generative Small Language Model *[STT]: Speech To Text: transformers with language model and CTC decoding *[THF]: TrulyHandsfree, Sensory's wake word and command recognition technology *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[VAD]: Voice Activity Detector --- source_path: "api/setting-keys/iterators.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators/" --- # Iterators Use these keys with [forEach](https://doc.sensory.com/tnl/7.8/api/inference.md#foreach) to loop over lists of values. The values for these settings refer to runtime instances of code objects and are not serialized by [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save) or [dup](https://doc.sensory.com/tnl/7.8/api/inference.md#dup). The [• results](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#results) and [• iterators](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators) available in the loop functions vary by iterator. See the descriptions below for details on what these are. Iterators are available only in the [• events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) listed, except for those marked as • _all_, which you can use outside of event callbacks too. Most applications don't use iterators directly — recognition results arrive via [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) without iteration. The two most useful when you do reach for them are [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) (per-word alignments and scores) and [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator) (model introspection); see the descriptions below for the rest. ### Details: Page conventions Settings are grouped by concern. Within each group they're listed alphabetically. A setting that serves more than one concern appears once under its primary group; secondary groups link to it. ## Wake word & command set ### model-iterator - iterator - handle - write-only **C/C++** ```c #define SNSR_MODEL_LIST "model-iterator" ``` **Java** ```java public class Snsr { public final static String MODEL_LIST = "model-iterator"; } ``` Iterate over the phoneme parts in a result. **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) **Available results:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample), [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score), [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) **Available iterators:** _none_ **Also see these related items:** [^phone-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phone-iterator), [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) ### operating-point-iterator - iterator - handle - write-only **C/C++** ```c #define SNSR_OPERATING_POINT_LIST "operating-point-iterator" ``` **Java** ```java public class Snsr { public final static String OPERATING_POINT_LIST = "operating-point-iterator"; } ``` Iterate over available spotter operating points. **Available in these events:** _all_ **Available results:** [available-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#available-point) **Available iterators:** _none_ ### phone-iterator - iterator - handle - write-only **C/C++** ```c #define SNSR_PHONE_LIST "phone-iterator" ``` **Java** ```java public class Snsr { public final static String PHONE_LIST = "phone-iterator"; } ``` Iterate over the phonemes in a result. STT models do not report any sub-word unit hypotheses. **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) **Available results:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample), [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score), [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) **Available iterators:** _none_ **Also see these related items:** [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) ### vocab-iterator - iterator - handle - write-only **C/C++** ```c #define SNSR_VOCAB_LIST "vocab-iterator" ``` **Java** ```java public class Snsr { public final static String VOCAB_LIST = "vocab-iterator"; } ``` Iterate over the vocabulary available in a keyword spotter. **Available in these events:** _all_ **Available results:** [id](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#id), [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) **Available iterators:** _none_ ### word-iterator - iterator - handle - write-only **C/C++** ```c #define SNSR_WORD_LIST "word-iterator" ``` **Java** ```java public class Snsr { public final static String WORD_LIST = "word-iterator"; } ``` Iterate over the words in a result. User-defined enrolled results are modeled as a single word. **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) **Available results:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample), [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score), [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) **Available iterators:** _none_ ## LVCSR & STT ### model-iterator - iterator - handle - write-only Documented under **Wake word & command set** ([model-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#model-iterator)). ### phone-iterator - iterator - handle - write-only Documented under **Wake word & command set** ([phone-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phone-iterator)). ### phrase-iterator - iterator - handle - write-only - tnl **C/C++** ```c #define SNSR_PHRASE_LIST "phrase-iterator" ``` **Java** ```java public class Snsr { public final static String PHRASE_LIST = "phrase-iterator"; } ``` Iterate over recognition phrase hypotheses. Most recognizers provide only the top-scoring recognition result. `phrase-iterator` is useful only when an LVCSR recognizer is configured to provide N-best results; when [result-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#result-max) `> 1`. **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) **Available results:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample), [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score), [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) **Available iterators:** _none_ **Also see these related items:** [result-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#result-max) ### word-iterator - iterator - handle - write-only Documented under **Wake word & command set** ([word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator)). ## NLU & SLM ### nlu-entity-iterator - iterator - handle - write-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_NLU_ENTITY_LIST "nlu-entity-iterator" ``` **Java** ```java public class Snsr { public final static String NLU_ENTITY_LIST = "nlu-entity-iterator"; } ``` Iterate over NLU entities in the current intent. This iterator invokes the specified handler for each of the [nlu-entity-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-count) entities found for the current intent. **Available in these events:** [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent) **Available results:** [nlu-entity-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-count), [nlu-entity-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-name), [nlu-entity-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-score), [nlu-entity-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-value) **Available iterators:** _none_ **Also see these related items:** [nlu-entity-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-count) ### nlu-slot-iterator - iterator - handle - write-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_NLU_SLOT_LIST "nlu-slot-iterator" ``` **Java** ```java public class Snsr { public final static String NLU_SLOT_LIST = "nlu-slot-iterator"; } ``` Iterate over NLU child result slots. This iterator invokes the specified handler for each of the NLU result slots found in the current NLU slot value, [nlu-slot-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-value). **Available in these events:** [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) **Available results:** [nlu-slot-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-count), [nlu-slot-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-name), [nlu-slot-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-score), [nlu-slot-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-value) **Available iterators:** [nlu-slot-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-slot-iterator) ### nlu-word-iterator - iterator - handle - write-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_NLU_WORD_LIST "nlu-word-iterator" ``` **Java** ```java public class Snsr { public final static String NLU_WORD_LIST = "nlu-word-iterator"; } ``` Iterate over the words in an NLU result. Valid only for LVCSR recognizers that include NLU post-processing. This post-processing can insert, delete, or change words in the recognition result and those changes are available here. **Available in these events:** [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent), [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) **Available results:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample), [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score), [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) **Available iterators:** _none_ **Also see these related items:** [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) ## Enrollment & adaptation ### enrollment-iterator - iterator - handle - write-only **C/C++** ```c #define SNSR_ENROLLMENT_LIST "enrollment-iterator" ``` **Java** ```java public class Snsr { public final static String ENROLLMENT_LIST = "enrollment-iterator"; } ``` Iterate over all wake word enrollments for the current user. This can be used to retrieve enrollment audio if [save-enroll-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#save-enroll-audio) is enabled. **Available in these events:** _all_ **Available results:** [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream), [audio-stream-first](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-first), [audio-stream-last](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-last), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample), [enrollment-id](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#enrollment-id), [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) **Available iterators:** _none_ **Also see these related items:** [save-enroll-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#save-enroll-audio), [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user), [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator) ### reason-iterator - iterator - handle - write-only **C/C++** ```c #define SNSR_REASON_LIST "reason-iterator" ``` **Java** ```java public class Snsr { public final static String REASON_LIST = "reason-iterator"; } ``` Iterate over all reasons for wake word enrollment failure. **Available in these events:** [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail) **Available results:** [reason](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason), [reason-guidance](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-guidance), [reason-pass](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-pass), [reason-threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-threshold), [reason-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-value) **Available iterators:** _none_ ### user-iterator - iterator - handle - write-only **C/C++** ```c #define SNSR_USER_LIST "user-iterator" ``` **Java** ```java public class Snsr { public final static String USER_LIST = "user-iterator"; } ``` Iterate over all enrolled users. Sets [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) to each of the enrolled users before invoking the callback. **Available in these events:** _all_ **Available results:** [enrollment-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#enrollment-count), [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) **Available iterators:** _none_ *[API]: Application Programming Interface *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[NLU]: Natural Language Understanding model *[SLM]: Generative Small Language Model *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/setting-keys/library-information.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information/" --- # Library information These keys return information about the library. They require a valid [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) but are available before loading a task model. Read information keys with the [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) `get` function that matches the type of the setting. For example, use [getString](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) to retrieve the _(string)_ value of [oss-components](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#oss-components). ## accel-info - information - string - read-only **C/C++** ```c #define SNSR_ACCELERATION "accel-info" ``` **Java** ```java public class Snsr { public final static String ACCELERATION = "accel-info"; } ``` Type of acceleration used. Returns text describing the type of vector acceleration the library uses. **Also see these related items:** [library-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-info) ## library-info - information - string - read-only **C/C++** ```c #define SNSR_LIBRARY_INFO "library-info" ``` **Java** ```java public class Snsr { public final static String LIBRARY_INFO = "library-info"; } ``` SDK library information. Human-readable summary of [NAME](https://doc.sensory.com/tnl/7.8/api/constants.md#name), [VERSION](https://doc.sensory.com/tnl/7.8/api/constants.md#version), [VERSION_DSP](https://doc.sensory.com/tnl/7.8/api/constants.md#version_dsp), [accel-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#accel-info), [license-exp-message](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#license-exp-message), [license-exp-warn](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#license-exp-warn), [stt-support](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#stt-support), [thread-support](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#thread-support), [LICENSE_SUPPORT](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_license_support), and [oss-components](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#oss-components). ## license-exp-date - information - double - read-only **C/C++** ```c #define SNSR_LICENSE_EXPDATE "license-exp-date" ``` **Java** ```java public class Snsr { public final static String LICENSE_EXPDATE = "license-exp-date"; } ``` Library license expiration date. Returns the license expiration date of the TrulyNatural library in seconds since the [epoch][]. For production keys, which do not expire, the expiration date is `0`. ## license-exp-message - information - string - read-only **C/C++** ```c #define SNSR_LICENSE_EXPIRES "license-exp-message" ``` **Java** ```java public class Snsr { public final static String LICENSE_EXPIRES = "license-exp-message"; } ``` Library license expiration message. The returned string is of the form `"Library license expires on "`, or `NULL` for license keys that do not expire. **Also see these related items:** [library-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-info) ## license-exp-warn - information - string - read-only **C/C++** ```c #define SNSR_LICENSE_WARNING "license-exp-warn" ``` **Java** ```java public class Snsr { public final static String LICENSE_WARNING = "license-exp-warn"; } ``` Library license expiration warning message. This value is `NULL` for library license keys that do not expire, or if the expiration date is more than 60 days into the future. For license keys expiring in 60 days or fewer, the returned string will be of the form `"License will expire in 37 days."`. **Also see these related items:** [library-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-info) ## oss-components - information - string - read-only **C/C++** ```c #define SNSR_OSS_COMPONENTS "oss-components" ``` **Java** ```java public class Snsr { public final static String OSS_COMPONENTS = "oss-components"; } ``` Open Source library acknowledgements. List of Open Source third-party modules linked into the binary. The returned string lists one module per newline-separated line. Each line contains the name of the library, the license type and a URL to the module license text, separated by tab characters. The TrulyNatural SDK uses [permissive software licenses][oss-permissive] only. If the binary uses no Open Source modules, the returned string is `NULL`. **Also see these related items:** [library-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-info), [Open Source Licenses](https://doc.sensory.com/tnl/7.8/licenses/oss.md#open-source-licenses) ## stt-support - information - int - read-only - since [7.5.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.5.0) **C/C++** ```c #define SNSR_STT_SUPPORT "stt-support" ``` **Java** ```java public class Snsr { public final static String STT_SUPPORT = "stt-support"; } ``` Library Speech-To-Text support. Returns `1` if the TrulyNatural SDK supports STT models, or `0 `if STT support is not available. This is functionally equivalent to calling [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) with [CONFIG_STT_SUPPORT](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_stt_support), but is available across all API language bindings. **Also see these related items:** [library-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-info), [CONFIG_STT_SUPPORT](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_stt_support) ## thread-support - information - int - read-only - since [7.5.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.5.0) **C/C++** ```c #define SNSR_THREAD_SUPPORT "thread-support" ``` **Java** ```java public class Snsr { public final static String THREAD_SUPPORT = "thread-support"; } ``` Library multithreading support. Returns `1` if the TrulyNatural SDK supports running multi-threaded models, or `0` if thread support is not available. This is functionally equivalent to calling [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) with [CONFIG_THREAD_SUPPORT](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_thread_support), but is available across all API language bindings. **Also see these related items:** [library-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-info), [CONFIG_THREAD_SUPPORT](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_thread_support) [epoch]: https://en.wikipedia.org/wiki/Unix_time "Unix time" [oss-permissive]: https://en.wikipedia.org/wiki/Permissive_software_license "Grants use rights, forbids almost nothing" *[API]: Application Programming Interface *[OSS]: Open-source software *[SDK]: Software Development Kit *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "api/setting-keys/results.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/setting-keys/results/" --- # Results These are read-only settings that report the results of model [inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference). The exact meaning depends on the context in which they are read. [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), for example, refers to the start time of a word in [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator), but to the onset of speech detection in [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end). Most results are valid only for the duration of the [• event](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) or [• iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#iterators) [callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback) handler where they are available in. If a result is shown as begin available in • _all_ events, you can also read it outside of event callbacks. Read results with the [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) `get` function that matches the type of the setting. For example, use [getDouble](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) to retrieve _(double)_ values. The handful of results most applications read: | Name | Type | Available in | Summary | |------|------|--------------|---------| | [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) | string | `^result`, `^result-partial`, `^slm-result*`; word and phrase iterators | Phrase, word, or phoneme hypothesis. | | [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score) | double | `^result`, `^result-partial`; word and phrase iterators | How well audio matches the recognizer; threshold for spotters. | | [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms) / [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms) | double | `^result`, `^result-partial`, `^begin`, `^end`, `^limit`; alignment iterators | Audio start / endpoint timestamps. | | [nlu-intent-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-name) | string | `^nlu-intent` | Top-level NLU intent. | | [nlu-intent-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-value) | string | `^nlu-intent` | Captured value for the current NLU intent. | Everything else on this page is either context-specific or rarely needed. ### Details: Page conventions Settings are grouped by concern. Within each group they're listed alphabetically. A setting that serves more than one concern appears once under its primary group; secondary groups link to it. ## Audio I/O ### audio-stream - result - output stream - read-only **C/C++** ```c #define SNSR_AUDIO_STREAM "audio-stream" ``` **Java** ```java public class Snsr { public final static String AUDIO_STREAM = "audio-stream"; } ``` Segmented audio data stream. * For enrollment tasks with [save-enroll-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#save-enroll-audio) is set to `1` (on) this is the enrollment recording. If [save-enroll-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#save-enroll-audio) is `0` (off), audio will only be available in the [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail) event. * For recognition tasks, the samples from [audio-stream-from](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-stream-from) to [audio-stream-to](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-stream-to) selected from the last [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size) samples processed by the recognizer. The default [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size) `0`, which disables audio buffering and will cause `audio-stream` retrieval to fail. Be sure to set [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size) to the expected number of samples before calling [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) or [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run). **Available in these events:** _all_ **Available in these iterators:** _all_ **Also see these related items:** [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [audio-stream-from](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-stream-from), [audio-stream-to](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-stream-to), [audio-stream-first](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-first), [audio-stream-last](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-last) ### audio-stream-first - result - double - read-only **C/C++** ```c #define SNSR_AUDIO_STREAM_FIRST "audio-stream-first" ``` **Java** ```java public class Snsr { public final static String AUDIO_STREAM_FIRST = "audio-stream-first"; } ``` Audio buffer start sample index. The index of the first (oldest) audio sample contained in the [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream). **Available in these events:** _all_ **Available in these iterators:** _all_ **Also see these related items:** [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream), [audio-stream-last](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-last) ### audio-stream-last - result - double - read-only **C/C++** ```c #define SNSR_AUDIO_STREAM_LAST "audio-stream-last" ``` **Java** ```java public class Snsr { public final static String AUDIO_STREAM_LAST = "audio-stream-last"; } ``` The index of the last (most recent) audio sample contained in the [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream). **Available in these events:** _all_ **Available in these iterators:** _all_ **Also see these related items:** [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream), [audio-stream-first](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-first) ### frame-count - configuration - double - read-only - pre-release **C/C++** ```c #define SNSR_RES_FRAMES "frame-count" ``` **Java** ```java public class Snsr { public final static String RES_FRAMES = "frame-count"; } ``` Number of feature frames read from the input stream. **Pre-release:** This is an experimental feature. Do not use unless recommended by Sensory. **Available in these events:** _all_ **Available in these iterators:** _all_ ### sample-count - result - double - read-only **C/C++** ```c #define SNSR_RES_SAMPLES "sample-count" ``` **Java** ```java public class Snsr { public final static String RES_SAMPLES = "sample-count"; } ``` Number of samples read from the input stream. **Available in these events:** _all_ **Available in these iterators:** _all_ **Also see these related items:** [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event) ## Wake word & command set ### available-point - result - int - read-only **C/C++** ```c #define SNSR_RES_AVAILABLE_POINT "available-point" ``` **Java** ```java public class Snsr { public final static String RES_AVAILABLE_POINT = "available-point"; } ``` Available operating point. **Available in these events:** _none_ **Available in these iterators:** [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator) **Also see these related items:** [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) ### confidence-score - result - double - read-only - deprecated [6.14.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.14.0) **C/C++** ```c #define SNSR_RES_CONF_SCORE "confidence-score" ``` **Java** ```java public class Snsr { public final static String RES_CONF_SCORE = "confidence-score"; } ``` Fixed-phrase wake word confidence score. **Deprecated:** Confidence score support will be removed from the next major release of this SDK. **Do not use this in new code.** The probability of the spotted phrase being a true accept. **This is a model-dependent optional feature not universally supported.** It is not supported by enrolled models, use [sv-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sv-score) instead. The reported range is `0` to `1`, or `< 0` if not supported by the spotter model. **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) **Available in these iterators:** _none_ **Also see these related items:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score), [sv-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sv-score) ### id - result - int - read-only **C/C++** ```c #define SNSR_RES_ID "id" ``` **Java** ```java public class Snsr { public final static String RES_ID = "id"; } ``` Recognition ID result. Unique wake word phrase result ID, compatible with THF Micro. For most single-phrase spotters this will be `1`. **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) **Available in these iterators:** [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator) **Also see these related items:** [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) ### noise-energy - result - double - read-only **C/C++** ```c #define SNSR_RES_NOISE_ENERGY "noise-energy" ``` **Java** ```java public class Snsr { public final static String RES_NOISE_ENERGY = "noise-energy"; } ``` Noise energy. The energy (in dB relative to `1.0`) in the background audio preceding the wake word audio. **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) **Available in these iterators:** _none_ **Also see these related items:** [signal-energy](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#signal-energy), [snr](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#snr) ### score - result - double - read-only **C/C++** ```c #define SNSR_RES_SCORE "score" ``` **Java** ```java public class Snsr { public final static String RES_SCORE = "score"; } ``` Recognition score. A value between `0` and `1` that indicates how well the acoustic evidence matches the recognizer's expectations. In phrase spotters that report this score, the operating point is set by thresholding this value. **Note:** `score` is not supported by all recognizer types. For older models, [getDouble](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) will report an [SETTING_NOT_FOUND](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) error. Recent models that do not support scoring report [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) and a score value of `-1.0` **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) **Available in these iterators:** [phone-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phone-iterator), [phrase-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phrase-iterator), [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) ### signal-energy - result - double - read-only **C/C++** ```c #define SNSR_RES_SIGNAL_ENERGY "signal-energy" ``` **Java** ```java public class Snsr { public final static String RES_SIGNAL_ENERGY = "signal-energy"; } ``` Signal energy. The energy (in dB relative to `1.0`) in the spotted phrase. **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) **Available in these iterators:** _none_ **Also see these related items:** [noise-energy](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#noise-energy), [snr](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#snr) ### snr - result - double - read-only **C/C++** ```c #define SNSR_RES_SNR "snr" ``` **Java** ```java public class Snsr { public final static String RES_SNR = "snr"; } ``` Signal to noise ratio. The ratio of the wake word signal energy to the noise energy, in dB. **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) **Available in these iterators:** _none_ **Also see these related items:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [noise-energy](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#noise-energy), [signal-energy](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#signal-energy) ### sv-score - result - double - read-only **C/C++** ```c #define SNSR_RES_SV_SCORE "sv-score" ``` **Java** ```java public class Snsr { public final static String RES_SV_SCORE = "sv-score"; } ``` Speaker verification score. The confidence that the spotted phrase was spoken by the enrolled speaker, in the range `0` to `1`. For non-enrolled spotters the confidence is always `1`. **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) **Available in these iterators:** _none_ **Also see these related items:** [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score), [sv-threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#sv-threshold) ### text - result - string - read-only **C/C++** ```c #define SNSR_RES_TEXT "text" ``` **Java** ```java public class Snsr { public final static String RES_TEXT = "text"; } ``` Recognition text result. The phrase, word, or phoneme hypothesis from a wake word, LVCSR, or STT recognizer. **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial), [^slm-result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result), [^slm-result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result-partial) **Available in these iterators:** [model-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#model-iterator), [nlu-word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-word-iterator), [phone-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phone-iterator), [phrase-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phrase-iterator), [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator), [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) ## LVCSR & STT ### result-count - result - int - read-only - tnl **C/C++** ```c #define SNSR_RES_COUNT "result-count" ``` **Java** ```java public class Snsr { public final static String RES_COUNT = "result-count"; } ``` Recognition result count. The total number of items available in the current list iteration. **Also see these related items:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [phrase-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phrase-iterator), [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) ### result-index - result - int - read-only - tnl **C/C++** ```c #define SNSR_RES_INDEX "result-index" ``` **Java** ```java public class Snsr { public final static String RES_INDEX = "result-index"; } ``` Recognition result index. The index of the item under consideration in the current list iteration. **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) **Available in these iterators:** [phrase-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phrase-iterator), [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) ### score - result - double - read-only Documented under **Wake word & command set** ([score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score)). ### text - result - string - read-only Documented under **Wake word & command set** ([text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text)). ## Alignment & timing ### begin-ms - result - double - read-only **C/C++** ```c #define SNSR_RES_BEGIN_MS "begin-ms" ``` **Java** ```java public class Snsr { public final static String RES_BEGIN_MS = "begin-ms"; } ``` Timestamp of the audio start point. The offset in ms from the beginning of the audio stream where: * the recognition unit started in [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) or [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial), or * the VAD first detected speech in [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin), [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end), or [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit). **Available in these events:** [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin), [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end), [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit), [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) **Available in these iterators:** [model-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#model-iterator), [nlu-word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-word-iterator), [phone-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phone-iterator), [phrase-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phrase-iterator), [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) **Also see these related items:** [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample) ### begin-sample - result - double - read-only **C/C++** ```c #define SNSR_RES_BEGIN_SAMPLE "begin-sample" ``` **Java** ```java public class Snsr { public final static String RES_BEGIN_SAMPLE = "begin-sample"; } ``` Sample index of the audio start point. The offset in samples from the beginning of the audio stream where: * the recognition unit started in [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) or [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial), or * the VAD first detected speech in [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin), [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end), or [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit). **Available in these events:** [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin), [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end), [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit), [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) **Available in these iterators:** [model-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#model-iterator), [nlu-word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-word-iterator), [phone-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phone-iterator), [phrase-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phrase-iterator), [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) **Also see these related items:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample) ### end-ms - result - double - read-only **C/C++** ```c #define SNSR_RES_END_MS "end-ms" ``` **Java** ```java public class Snsr { public final static String RES_END_MS = "end-ms"; } ``` Timestamp of the audio endpoint. The offset in ms from the beginning of the audio stream: * where the recognition unit ended in [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), or * the VAD last detected speech in [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end) or [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit). **Available in these events:** [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end), [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit), [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) **Available in these iterators:** [model-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#model-iterator), [nlu-word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-word-iterator), [phone-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phone-iterator), [phrase-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phrase-iterator), [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) **Also see these related items:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample) ### end-sample - result - double - read-only **C/C++** ```c #define SNSR_RES_END_SAMPLE "end-sample" ``` **Java** ```java public class Snsr { public final static String RES_END_SAMPLE = "end-sample"; } ``` Sample index of the audio endpoint. The offset in samples from the beginning of the audio stream: * where the recognition unit ended in [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), or * the VAD last detected speech in [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end) or [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit). **Available in these events:** [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end), [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit), [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) **Available in these iterators:** [model-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#model-iterator), [nlu-word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-word-iterator), [phone-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phone-iterator), [phrase-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phrase-iterator), [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator) **Also see these related items:** [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms) ## NLU & SLM ### domain - result - string - read-only _(stt)_ _(since [7.5.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.5.0))_ **C/C++** ```c #define SNSR_RES_DOMAIN "domain" ``` **Java** ```java public class Snsr { public final static String RES_DOMAIN = "domain"; } ``` STT recognition domain. This is short label identifying the domain identified by the STT recognizer, for example: `automotive` or `numbers`. This value is `NULL` if the recognizer does not support multiple domains. **Available in these events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) **Available in these iterators:** _none_ **Also see these related items:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) ### nlu-entity-count - result - int - read-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_RES_NLU_ENTITY_COUNT "nlu-entity-count" ``` **Java** ```java public class Snsr { public final static String RES_NLU_ENTITY_COUNT = "nlu-entity-count"; } ``` Number of NLU entities available. Reports the number of entities the current [nlu-intent-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-value) contains. An entity is typically an object that an intent action operates on. **Available in these events:** [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent) **Available in these iterators:** [nlu-entity-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-entity-iterator) **Also see these related items:** [nlu-entity-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-name), [nlu-entity-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-score), [nlu-entity-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-value), [nlu-intent-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-value) ### nlu-entity-name - result - string - read-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_RES_NLU_ENTITY_NAME "nlu-entity-name" ``` **Java** ```java public class Snsr { public final static String RES_NLU_ENTITY_NAME = "nlu-entity-name"; } ``` Name of the current entity. Valid only in [nlu-entity-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-entity-iterator) callback handlers. **Available in these events:** _none_ **Available in these iterators:** [nlu-entity-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-entity-iterator) **Also see these related items:** [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent), [nlu-entity-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-score), [nlu-entity-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-value) ### nlu-entity-score. - result - string - read-only - stt **C/C++** ```c #define SNSR_RES_NLU_ENTITY_SCORE "nlu-entity-score." ``` **Java** ```java public class Snsr { public final static String RES_NLU_ENTITY_SCORE = "nlu-entity-score."; } ``` Score of the current entity. Reports the confidence the model has that this entity was classified correctly. Not all NLU models report scores. If the score is not available it is reported as `0`. If you know the name of the entity, you can retrieve the value directly without having to use [nlu-entity-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-entity-iterator) by appending the name to `nlu-entity-score.` **Example:** **C/C++** ```c double score; snsrGetDouble(session, SNSR_RES_NLU_ENTITY_SCORE "alarm.time", &score); ``` **Java** ```java double score = session.getDouble(Snsr.RES_NLU_ENTITY_SCORE + "alarm.time"); ``` **Available in these events:** [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent) **Available in these iterators:** [nlu-entity-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-entity-iterator) **Also see these related items:** [nlu-entity-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-name), [nlu-entity-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-value) ### nlu-entity-value. - result - string - read-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_RES_NLU_ENTITY_VALUE "nlu-entity-value." ``` **Java** ```java public class Snsr { public final static String RES_NLU_ENTITY_VALUE = "nlu-entity-value."; } ``` Captured value of the current entity. If you know the name of the entity, you can retrieve the value directly without having to use [nlu-entity-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-entity-iterator) by appending the name to `nlu-entity-value.` **Example:** **C/C++** ```c char *atime; snsrGetString(session, SNSR_RES_NLU_ENTITY_VALUE "alarm.time", &atime); ``` **Java** ```java String atime = session.getString(Snsr.RES_NLU_ENTITY_VALUE + "alarm.time"); ``` **Available in these events:** [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent) **Available in these iterators:** [nlu-entity-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-entity-iterator) **Also see these related items:** [nlu-entity-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-name), [nlu-entity-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-score) ### nlu-intent-name - result - string - read-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_RES_NLU_INTENT_NAME "nlu-intent-name" ``` **Java** ```java public class Snsr { public final static String RES_NLU_INTENT_NAME = "nlu-intent-name"; } ``` The name of the current NLU intent. **Available in these events:** [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent) **Available in these iterators:** _none_ **Also see these related items:** [nlu-intent-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-value), [nlu-intent-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-score) ### nlu-intent-score - result - double - read-only - stt **C/C++** ```c #define SNSR_RES_NLU_INTENT_SCORE "nlu-intent-score" ``` **Java** ```java public class Snsr { public final static String RES_NLU_INTENT_SCORE = "nlu-intent-score"; } ``` Score of the current NLU intent. Reports the confidence the model has that the intent was classified correctly. Not all NLU models report scores. If the score is not available it is reported as `0`. **Available in these events:** [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent) **Available in these iterators:** _none_ **Also see these related items:** [nlu-intent-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-name), [nlu-intent-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-value) ### nlu-intent-value - result - string - read-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_RES_NLU_INTENT_VALUE "nlu-intent-value" ``` **Java** ```java public class Snsr { public final static String RES_NLU_INTENT_VALUE = "nlu-intent-value"; } ``` Captured value of the current NLU intent. This is the part of the recognition result classified as the current intent. **Available in these events:** [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent) **Available in these iterators:** _none_ **Also see these related items:** [nlu-intent-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-name), [nlu-intent-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-score) ### nlu-match-count - result - int - read-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_RES_NLU_COUNT "nlu-match-count" ``` **Java** ```java public class Snsr { public final static String RES_NLU_COUNT = "nlu-match-count"; } ``` Number of NLU result matches available. Reports the number of NLU matches that are available for this result. The available matches are capped by [nlu-match-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-match-max). Multiple matches are only possible when there's ambiguity in the NLU grammar: One input sequence matches multiple output sequences, or when the `.*` match-any-word operator results in multiple valid segmentations. **Example:** ``` g = {first .*} {second .*} ; ``` **Available in these events:** [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) **Available in these iterators:** _none_ **Also see these related items:** [nlu-match-index](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-match-index), [nlu-match-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-match-max) ### nlu-match-index - result - int - read-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_RES_NLU_INDEX "nlu-match-index" ``` **Java** ```java public class Snsr { public final static String RES_NLU_INDEX = "nlu-match-index"; } ``` The current NLU match index. Reports the current NLU match for [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot). The best-scoring match will have `nlu-match-index == 0`. **Available in these events:** [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) **Available in these iterators:** _none_ **Also see these related items:** [nlu-match-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-match-count), [nlu-match-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-match-max) ### nlu-slot-count - result - int - read-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_RES_NLU_SLOT_COUNT "nlu-slot-count" ``` **Java** ```java public class Snsr { public final static String RES_NLU_SLOT_COUNT = "nlu-slot-count"; } ``` Number of NLU child slots available. Reports the number of child slots the current [nlu-slot-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-value) contains. For final value slots this count is `0`. **Available in these events:** [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) **Available in these iterators:** [nlu-slot-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-slot-iterator) **Also see these related items:** [nlu-slot-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-name), [nlu-slot-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-score), [nlu-slot-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-value) ### nlu-slot-name - result - string - read-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_RES_NLU_SLOT_NAME "nlu-slot-name" ``` **Java** ```java public class Snsr { public final static String RES_NLU_SLOT_NAME = "nlu-slot-name"; } ``` Name of the current NLU slot. **Available in these events:** [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) **Available in these iterators:** [nlu-slot-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-slot-iterator) **Also see these related items:** [nlu-slot-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-score), [nlu-slot-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-value) ### nlu-slot-score. - result - double - read-only - stt **C/C++** ```c #define SNSR_RES_NLU_SLOT_SCORE "nlu-slot-score." ``` **Java** ```java public class Snsr { public final static String RES_NLU_SLOT_SCORE = "nlu-slot-score."; } ``` Score of the current NLU slot. Reports the confidence the model has that this slot was classified correctly. Not all NLU models report scores. If the score is not available it is reported as `0`. If you know the name of the (possibly nested) slot, you can retrieve the value directly without having to use [nlu-slot-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-slot-iterator). Separate slot names in the hierarchy with a period. **Example:** **C/C++** ```c double score; snsrGetDouble(session, SNSR_RES_NLU_SLOT_SCORE "alarm.time", &score); ``` **Java** ```java double score = session.getDouble(Snsr.RES_NLU_SLOT_SCORE + "alarm.time"); ``` **Available in these events:** [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) **Available in these iterators:** [nlu-slot-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-slot-iterator) **Also see these related items:** [nlu-slot-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-name), [nlu-slot-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-value) ### nlu-slot-value. - result - string - read-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_RES_NLU_SLOT_VALUE "nlu-slot-value." ``` **Java** ```java public class Snsr { public final static String RES_NLU_SLOT_VALUE = "nlu-slot-value."; } ``` Captured value of the current NLU slot. Use `nlu-slot-value` to retrieve the string value of the current NLU slot. If you know the name of the (possibly nested) slot, you can retrieve the value directly without having to use [nlu-slot-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-slot-iterator) Separate slot names in the hierarchy with a period. **Example:** With this grammar: ``` ampm = am | pm; time = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; alarm = set the alarm for {time} {ampm}; grammar = {alarm} ; ``` Use this code snippet to retrieve the time and am/pm slot values in the [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) callback: **C/C++** ```c const char *timeHours; const char *ampm; snsrGetString(session, SNSR_RES_NLU_SLOT_VALUE "alarm.time", &timeHours); snsrGetString(session, SNSR_RES_NLU_SLOT_VALUE "alarm.ampm", &m); ``` **Java** ```java String timeHours = session.getString(Snsr.RES_NLU_SLOT_VALUE + "alarm.time"); String ampm = session.getString(Snsr.RES_NLU_SLOT_VALUE + "alarm.ampm"); ``` **Available in these events:** [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) **Available in these iterators:** [nlu-slot-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-slot-iterator) **Also see these related items:** [nlu-slot-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-count), [nlu-slot-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-name) ### text - result - string - read-only Documented under **Wake word & command set** ([text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text)). SLM results are reported via this key; NLU intents use [nlu-intent-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-name) and [nlu-intent-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-value) instead. ## Enrollment & adaptation ### enrollment-count - result - int - read-only **C/C++** ```c #define SNSR_RES_ENROLLMENT_COUNT "enrollment-count" ``` **Java** ```java public class Snsr { public final static String RES_ENROLLMENT_COUNT = "enrollment-count"; } ``` Enrollment count. The number of enrollments accumulated for the enrolled user. **Available in these events:** _none_ **Available in these iterators:** [enrollment-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#enrollment-iterator), [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator) **Also see these related items:** [req-enroll](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#req-enroll), [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator) ### enrollment-id - result - int - read-only **C/C++** ```c #define SNSR_RES_ENROLLMENT_ID "enrollment-id" ``` **Java** ```java public class Snsr { public final static String RES_ENROLLMENT_ID = "enrollment-id"; } ``` Enrollment ID. A unique ID for the current user's current enrollment. **Available in these events:** [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail), [^pass](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#pass) **Available in these iterators:** [enrollment-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#enrollment-iterator) ### model-stream - result - output stream - read-only **C/C++** ```c #define SNSR_MODEL_STREAM "model-stream" ``` **Java** ```java public class Snsr { public final static String MODEL_STREAM = "model-stream"; } ``` Enrolled wake word model stream. The result after enrollment and adaptation. This is a model that will recognize the enrolled phrases. Save to permanent storage with [copy](https://doc.sensory.com/tnl/7.8/api/io.md#stream-copy). Retrieving the model stream will fail with [SETTING_NOT_AVAILABLE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) if there are no enrolled users. **Available in these events:** [^done](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#done) **Available in these iterators:** _none_ ### percent-done - result - double - read-only **C/C++** ```c #define SNSR_RES_PERCENT_DONE "percent-done" ``` **Java** ```java public class Snsr { public final static String RES_PERCENT_DONE = "percent-done"; } ``` Enrollment progress. A value between `0` and `100` that is an estimate of the enrollment task completion progress. **Available in these events:** [^progress](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#progress) **Available in these iterators:** _none_ **Also see these related items:** [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), [^enrolled](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#enrolled) ### reason - result - string - read-only **C/C++** ```c #define SNSR_RES_REASON "reason" ``` **Java** ```java public class Snsr { public final static String RES_REASON = "reason"; } ``` Reason for enrollment failure. Provides a shorthand indication of why a wake word enrollment was rejected. Reason | Guidance -------|--------- `energy-min` | Please speak louder. `energy-stddev` | This recording does not sound like speech. `silence-begin` | Please wait for the prompt before speaking. `silence-end` | The trailing silence too short. `snr` | The recording is too noisy. Please move to a quieter environment. `rec-variance` | The difference between the recordings is too large. Please repeat the exact same phrase. `poor-rec-limit` | The recording may not contain speech. Please speak a consistent trigger. `clipping` | The recording is clipped, please reduce the volume. `vowel-duration` | Please speak more slowly, or choose a different phrase with more vowel sounds. `repetition` | This phrase has too many repeated sounds. Please choose another. `silence-in-phrase` | Please don't pause - even briefly - in the middle of the recording. `spot` | Please say the exact enrollment phrase, speaking clearly and naturally. `phrase-quality` | This phrase is not suitable, please choose another or speak a little more slowly. `audio-quality` | The enrollment shows signs of problems with the audio hardware. `audio-duration` | The enrollment recording is too short. `audio-volume` | No audio detected. Please speak louder. `audio-failure` | _varies_ *All `reason` values and corresponding guidance* **Available in these events:** [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail) **Available in these iterators:** [reason-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#reason-iterator) **Also see these related items:** [reason-guidance](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-guidance) ### reason-guidance - result - string - read-only **C/C++** ```c #define SNSR_RES_GUIDANCE "reason-guidance" ``` **Java** ```java public class Snsr { public final static String RES_GUIDANCE = "reason-guidance"; } ``` End-user guidance to correct a wake word enrollment failure. Provides a human-readable string (in English) with a suggestion on how to correct an enrollment failure. **Available in these events:** [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail) **Available in these iterators:** [reason-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#reason-iterator) **Also see these related items:** [reason](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason) ### reason-pass - result - int - read-only **C/C++** ```c #define SNSR_RES_REASON_PASS "reason-pass" ``` **Java** ```java public class Snsr { public final static String RES_REASON_PASS = "reason-pass"; } ``` Enrollment success. `1` if the enrollment passed, `0` if it was rejected. ### reason-threshold - result - double - read-only **C/C++** ```c #define SNSR_RES_REASON_THRESHOLD "reason-threshold" ``` **Java** ```java public class Snsr { public final static String RES_REASON_THRESHOLD = "reason-threshold"; } ``` Enrollment check threshold value. **Available in these events:** [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail) **Available in these iterators:** [reason-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#reason-iterator) **Also see these related items:** [reason-pass](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-pass), [reason-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-value) ### reason-value - result - double - read-only **C/C++** ```c #define SNSR_RES_REASON_VALUE "reason-value" ``` **Java** ```java public class Snsr { public final static String RES_REASON_VALUE = "reason-value"; } ``` Enrollment check failure value. The value of an enrollment check parameter. This is compared to [reason-threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-threshold) to determine [reason-pass](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-pass). **Available in these events:** [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail) **Available in these iterators:** [reason-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#reason-iterator) **Also see these related items:** [reason-pass](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-pass), [reason-threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason-threshold) ### user-count - result - int - read-only **C/C++** ```c #define SNSR_RES_USER_COUNT "user-count" ``` **Java** ```java public class Snsr { public final static String RES_USER_COUNT = "user-count"; } ``` Enrolled user count. The number of distinct enrolled users. This setting is only available for [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot) models that continuously adapt to speakers' voices. **Available in these events:** [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), [^new-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#new-user) **Available in these iterators:** _none_ ### user-index - result - int - read-only **C/C++** ```c #define SNSR_RES_USER_INDEX "user-index" ``` **Java** ```java public class Snsr { public final static String RES_USER_INDEX = "user-index"; } ``` Enrolled user index. The index of the item under consideration in the current user list iteration. **Available in these events:** _none_ **Available in these iterators:** [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator) ## THF Micro DSP ### dsp.production-ready - result - int - read-only **C/C++** ```c #define SNSR_RES_EMBEDDED_MODEL_PRODUCTION_READY "dsp.production-ready" ``` **Java** ```java public class Snsr { public final static String RES_EMBEDDED_MODEL_PRODUCTION_READY = "dsp.production-ready"; } ``` Whether the DSP model files are suitable for production use. Possible values: `0`: The [dsp-acmodel-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-acmodel-stream) has enforced event limits. The model will stop working after a pre-determined number of recognition events, or audio samples processed. *This model is not suitable for production use.* `1`: The [dsp-acmodel-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-acmodel-stream) is not limited, and can be used in products. **Note:** This read-only value is valid only after a [dsp-header-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-header-stream) conversion is complete. **Available in these events:** _all_ **Available in these iterators:** _all_ **Also see these related items:** [dsp-acmodel-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-acmodel-stream), [dsp.t-slice-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#dspt-slice-version) ### dsp.t-slice-version - result - string - read-only **C/C++** ```c #define SNSR_RES_MIN_EMBEDDED_VERSION "dsp.t-slice-version" ``` **Java** ```java public class Snsr { public final static String RES_MIN_EMBEDDED_VERSION = "dsp.t-slice-version"; } ``` Embedded port version. This is the minimum version of the embedded port (also known as the t-slice version) required to run the [dsp-acmodel-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-acmodel-stream) and [dsp-search-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-search-stream) DSP data files. **Note:** This read-only value is valid only after a [dsp-acmodel-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-acmodel-stream) conversion is complete. **Available in these events:** _all_ **Available in these iterators:** _all_ **Also see these related items:** [dsp-acmodel-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-acmodel-stream), [dsp.production-ready](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#dspproduction-ready), [dsp-target](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-target) ## Logging & diagnostics ### profile:real-time - result - double - read-only **C/C++** ```c #define SNSR_RES_CPU_SECONDS_USED "profile:real-time" ``` **Java** ```java public class Snsr { public final static String RES_CPU_SECONDS_USED = "profile:real-time"; } ``` Seconds spent in model inference since last reset. Reports the number of wall-clock seconds spent running the model, or [template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) slot in a model. This depends on having a usable real-time clock implementation. **Available in these events:** _none_ **Available in these iterators:** _none_ **Also see these related items:** [profile](https://doc.sensory.com/tnl/7.8/api/inference.md#profile), [CONFIG_CLOCK_FUNC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_clock_func) ### profile:samples - result - double - read-only - since [7.8.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.8.0) **C/C++** ```c #define SNSR_RES_SAMPLES_PROCESSED "profile:samples" ``` **Java** ```java public class Snsr { public final static String RES_SAMPLES_PROCESSED = "profile:samples"; } ``` Number of samples processed since last reset. Reports the number of audio samples processed while running a model, or [template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) slot in a model. When used without a slot prefix `profile:samples` returns the same value as [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count). **Available in these events:** _none_ **Available in these iterators:** _none_ **Also see these related items:** [profile](https://doc.sensory.com/tnl/7.8/api/inference.md#profile), [profile:real-time](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#profilereal-time), [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) *[API]: Application Programming Interface *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[NLU]: Natural Language Understanding model *[SDK]: Software Development Kit *[SLM]: Generative Small Language Model *[STT]: Speech To Text: transformers with language model and CTC decoding *[THF]: TrulyHandsfree, Sensory's wake word and command recognition technology *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[VAD]: Voice Activity Detector --- source_path: "api/setting-keys/runtime.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime/" --- # Runtime These settings inspect the state, or change the behavior, of [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) object instances. They are not serialized by [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save) or [dup](https://doc.sensory.com/tnl/7.8/api/inference.md#dup). Most applications will use [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm) with [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) or [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) to present audio samples to a recognition task. Other runtime keys come up only in specific workflows: [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream) and [phrases-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#phrases-stream) for custom LVCSR vocabularies, [dsp-target](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-target) for THF Micro export, and [add-context](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#add-context) / [delete-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#delete-user) / [rename-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#rename-user) for enrollment. Access runtime settings with the [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) `get` or `set` function that matches the setting type. For example, use [setStream](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) to change the _(input stream)_ for [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm). ### Details: Page conventions Settings are grouped by concern. Within each group they're listed alphabetically. A setting that serves more than one concern appears once under its primary group; secondary groups link to it. ## Audio I/O ### ->audio-pcm - runtime - input stream - write-only **C/C++** ```c #define SNSR_SOURCE_AUDIO_PCM "->audio-pcm" ``` **Java** ```java public class Snsr { public final static String SOURCE_AUDIO_PCM = "->audio-pcm"; } ``` Input audio stream. This audio stream must be headerless, 16-bit LPCM-encoded, sampled at 16 kHz, with little-endian byte ordering. **Also see these related items:** [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) ### ->feature - runtime - input stream - write-only - pre-release **C/C++** ```c #define SNSR_SOURCE_FEATURE "->feature" ``` **Java** ```java public class Snsr { public final static String SOURCE_FEATURE = "->feature"; } ``` Input feature stream. **Pre-release:** This is an experimental feature. Do not use unless recommended by Sensory. Source stream in a proprietary Sensory format. ### <-audio-pcm - runtime - output stream - write-only **C/C++** ```c #define SNSR_SINK_AUDIO_PCM "<-audio-pcm" ``` **Java** ```java public class Snsr { public final static String SINK_AUDIO_PCM = "<-audio-pcm"; } ``` Output audio stream. Headerless audio output, 16-bit LPCM-encoded, sampled at 16 kHz, with little-endian byte ordering. ### <-feature - runtime - output stream - write-only - pre-release **C/C++** ```c #define SNSR_SINK_FEATURE "<-feature" ``` **Java** ```java public class Snsr { public final static String SINK_FEATURE = "<-feature"; } ``` Output feature stream. **Pre-release:** This is an experimental feature. Do not use unless recommended by Sensory. Headerless feature output in a proprietary Sensory format. ### audio-stream-from - runtime - double - read-write **C/C++** ```c #define SNSR_AUDIO_STREAM_FROM "audio-stream-from" ``` **Java** ```java public class Snsr { public final static String AUDIO_STREAM_FROM = "audio-stream-from"; } ``` Audio stream requested start index. Start the next [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream) at this sample index value. Defaults to [audio-stream-first](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-first). **Also see these related items:** [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream), [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size) ### audio-stream-to - runtime - double - read-write **C/C++** ```c #define SNSR_AUDIO_STREAM_TO "audio-stream-to" ``` **Java** ```java public class Snsr { public final static String AUDIO_STREAM_TO = "audio-stream-to"; } ``` Audio stream requested end index. End the next [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream) at this sample index value. Defaults to [audio-stream-last](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-last). **Also see these related items:** [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream), [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size) ## VAD & endpointing ### skip-to-ms - runtime - int - write-only **C/C++** ```c #define SNSR_SKIP_TO_MS "skip-to-ms" ``` **Java** ```java public class Snsr { public final static String SKIP_TO_MS = "skip-to-ms"; } ``` VAD initial ignore duration, in ms. Ignore the first `skip-to-ms` ms of the [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm) input stream. Use this runtime setting to skip over a trigger phrase included in the source audio. The default is to process all audio. **Also see these related items:** [skip-to-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#skip-to-sample) ### skip-to-sample - runtime - int - write-only **C/C++** ```c #define SNSR_SKIP_TO_SAMPLE "skip-to-sample" ``` **Java** ```java public class Snsr { public final static String SKIP_TO_SAMPLE = "skip-to-sample"; } ``` VAD initial ignore duration, in samples. Ignore the first `skip-to-sample` samples of the [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm) input stream. Use this runtime setting to skip over a trigger phrase included in the source audio. The default is to process all audio. **Also see these related items:** [skip-to-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#skip-to-ms) ## LVCSR & STT ### grammar-stream. - runtime - input stream - write-only - tnl **C/C++** ```c #define SNSR_GRAMMAR_STREAM "grammar-stream." ``` **Java** ```java public class Snsr { public final static String GRAMMAR_STREAM = "grammar-stream."; } ``` Recognition grammar stream. Creates a recognizer from a grammar specification read from a stream. The grammar must use [UTF‑8][UTF-8] encoding. The new model will recognize only those phrases that the grammar generates. The model will be ready to recognize once [setStream](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) returns. For larger grammars the build process can take a significant amount of time. See [grammar syntax](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-syntax) for detail on how grammars are structured. To create a grammar for a class, append the class name to `grammar-stream.`: **Example:** **C/C++** ```c snsrSetStream(session, SNSR_GRAMMAR_STREAM "classname", grammarStream); ``` **Java** ```java session.set(Snsr.GRAMMAR_STREAM + "classname", grammarStream); ``` **Note:** Requires a TrulyNatural model that supports building. **Also see these related items:** [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream), [phrases-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#phrases-stream) ### nlu-grammar-stream. - runtime - input stream - write-only _(tnl)_ _(stt)_ **C/C++** ```c #define SNSR_NLU_GRAMMAR_STREAM "nlu-grammar-stream." ``` **Java** ```java public class Snsr { public final static String NLU_GRAMMAR_STREAM = "nlu-grammar-stream."; } ``` NLU grammar stream. Creates a lightweight NLU parser from a grammar specification read from a stream. It takes precedence over NLU specified with [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream) and can be used as an alternative to machine-learned NLU in some STT models. The grammar must use [UTF‑8][UTF-8] encoding. The NLU model will recognize only those phrases that the grammar generates. The NLU parser is applied to the recognition result, [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), and generates [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent) and [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) events for each match found. The model will be ready to recognize once [setStream](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) returns. For larger grammars the build process can take a significant amount of time. See [grammar syntax](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-syntax) for detail on how grammars are structured. To create a grammar for a class, append the class name to `nlu-grammar-stream.`: **Example:** **C/C++** ```c snsrSetStream(session, SNSR_NLU_GRAMMAR_STREAM "classname", grammarStream); ``` **Java** ```java SnsrSession.set(Snsr.NLU_GRAMMAR_STREAM + "classname", grammarStream); ``` **Note:** * Requires a TrulyNatural model that supports building. * _(since [7.8.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.8.0))_ If the model includes a machine-learned NLU component and the grammar-based NLU finds a match, this match replaces the machine learned-result completely. Before release 7.8.0 the `nlu-grammar-stream` result replaced the machine-learned result even if it found no matches. **Also see these related items:** [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream), [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent), [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) ### phrases-stream. - runtime - input stream - write-only - tnl **C/C++** ```c #define SNSR_PHRASES_STREAM "phrases-stream." ``` **Java** ```java public class Snsr { public final static String PHRASES_STREAM = "phrases-stream."; } ``` Recognition phrase list stream. Creates a recognizer from a list of phrases read from a stream. The phrase list must use [UTF‑8][UTF-8] encoding. Individual phrases are separated by newlines or semicolons. Comments start with `#` and run until the end of the phrase. Only the exact phrases in the list will be part of the recognition language. This utility setting converts the list of phrases into this grammar specification: ``` g = ( phrase0 | phrase1 | ... | phraseN) ; ``` To create a phrase list for a class, append the class name to `phrases-stream.`: **Example:** **C/C++** ```c const char *phrases = "hello world; this is a test sentence"; snsrSetStream(session, SNSR_PHRASES_STREAM "classname", snsrStreamFromString(phrases)); ``` **Java** ```java String phrases = "hello world; this is a test sentence"; session.set(Snsr.PHRASES_STREAM + "classname", SnsrStream.fromString(phrases)); ``` **Note:** Requires a TrulyNatural model that supports building. **Also see these related items:** [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream), [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream) ## Enrollment & adaptation ### add-context - runtime - int - read-write **C/C++** ```c #define SNSR_ADD_CONTEXT "add-context" ``` **Java** ```java public class Snsr { public final static String ADD_CONTEXT = "add-context"; } ``` Current enrollment includes trailing context. Set to `1` if the enrollment recording should include trailing context, for example: `"Hey Sensory will it rain tomorrow?"` **Also see these related items:** [^resume](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#resume) ### delete-user - runtime - string - write-only **C/C++** ```c #define SNSR_DELETE_USER "delete-user" ``` **Java** ```java public class Snsr { public final static String DELETE_USER = "delete-user"; } ``` Delete an enrolled user. Deletes the named user, then: * invokes [^enrolled](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#enrolled) event, * invokes [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted) event iff any enrolled users remain, * invokes [^done](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#done) event. **Also see these related items:** [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), [^done](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#done), [^enrolled](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#enrolled) ### re-adapt - runtime - int - write-only **C/C++** ```c #define SNSR_RE_ADAPT "re-adapt" ``` **Java** ```java public class Snsr { public final static String RE_ADAPT = "re-adapt"; } ``` Force re-adaptation of all enrollments. If all users in an enrollment task have been adapted, the adaptation step is skipped. This is the case when one or more adapted enrollment contexts are loaded, and no new users are added. Setting `re-adapt` to `1` changes this behavior to always do the adaptation step. **Also see these related items:** [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted) ### rename-user - runtime - string - write-only **C/C++** ```c #define SNSR_RENAME_USER "rename-user" ``` **Java** ```java public class Snsr { public final static String RENAME_USER = "rename-user"; } ``` Rename an enrolled user. Changes the recognition result returned for [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) to the string argument. This setting is only available in fixed-phrase spotters that support continuous adaptation. **Example:** **C/C++** ```c snsrSetString(s, SNSR_USER, "original-user/phrase"); snsrSetString(s, SNSR_RENAME_USER, "new-user/new-phrase"); ``` **Java** ```java session.setString(Snsr.USER, "original-user/phrase"); session.setString(Snsr.RENAME_USER, "new-user/new-phrase"); ``` **Also see these related items:** [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), [^new-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#new-user) ## Push / pull execution ### auto-flush - runtime - int - read-write - deprecated [6.20.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.20.0) **C/C++** ```c #define SNSR_AUTO_FLUSH "auto-flush" ``` **Java** ```java public class Snsr { public final static String AUTO_FLUSH = "auto-flush"; } ``` Recognition pipeline end-of-stream flush behavior. **Deprecated:** Use [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) and [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop) in new code instead. This boolean value controls whether [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) flushes the recognition pipeline when one (or more) of the input streams report an end-of-file condition. The default value is `1`, which enables automatic flushing on [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof). This is appropriate for most applications. Set `auto-flush` to `0` when audio is presented to [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) in small segments. **Also see these related items:** [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run), [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop) ## THF Micro DSP ### dsp-acmodel-stream - runtime - output stream - read-only **C/C++** ```c #define SNSR_EMBEDDED_ACMODEL_STREAM "dsp-acmodel-stream" ``` **Java** ```java public class Snsr { public final static String EMBEDDED_ACMODEL_STREAM = "dsp-acmodel-stream"; } ``` Embedded device acoustic model data. **Also see these related items:** [dsp-target](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-target), [dsp-header-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-header-stream), [dsp-search-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-search-stream), [dsp.production-ready](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#dspproduction-ready), [dsp.t-slice-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#dspt-slice-version) ### dsp-header-stream - runtime - output stream - read-only **C/C++** ```c #define SNSR_EMBEDDED_HEADER_STREAM "dsp-header-stream" ``` **Java** ```java public class Snsr { public final static String EMBEDDED_HEADER_STREAM = "dsp-header-stream"; } ``` Embedded device search header. **Also see these related items:** [dsp-target](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-target),[dsp-acmodel-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-acmodel-stream), [dsp-search-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-search-stream), [dsp.t-slice-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#dspt-slice-version) ### dsp-search-stream - runtime - output stream - read-only **C/C++** ```c #define SNSR_EMBEDDED_SEARCH_STREAM "dsp-search-stream" ``` **Java** ```java public class Snsr { public final static String EMBEDDED_SEARCH_STREAM = "dsp-search-stream"; } ``` Embedded device search model data. **Also see these related items:** [dsp-target](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-target), [dsp-acmodel-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-acmodel-stream), [dsp-header-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-header-stream), [dsp.t-slice-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#dspt-slice-version) ### dsp-target - runtime - string - read-write **C/C++** ```c #define SNSR_EMBEDDED_TARGET "dsp-target" ``` **Java** ```java public class Snsr { public final static String EMBEDDED_TARGET = "dsp-target"; } ``` Embedded (DSP) device target name. **Also see these related items:** [dsp-acmodel-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-acmodel-stream), [dsp-header-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-header-stream), [dsp-search-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-search-stream), [dsp.t-slice-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#dspt-slice-version) ## Identity & metadata ### model-license-exp-date - runtime - double - read-only **C/C++** ```c #define SNSR_MODEL_LICENSE_EXPDATE "model-license-exp-date" ``` **Java** ```java public class Snsr { public final static String MODEL_LICENSE_EXPDATE = "model-license-exp-date"; } ``` Model license expiration date. Returns the license expiration date of the most recently loaded model in seconds since the [epoch][], or `0` if no model is loaded. For production keys, which never expire, the expiration date is `0`. **Example:** ```c double e; time_t expdate; snsrGetDouble(s, SNSR_MODEL_LICENSE_EXPDATE, &e); expdate = (time_t)e; ``` **Also see these related items:** [model-license-exp-message](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#model-license-exp-message) ### model-license-exp-message - runtime - string - read-only **C/C++** ```c #define SNSR_MODEL_LICENSE_EXPIRES "model-license-exp-message" ``` **Java** ```java public class Snsr { public final static String MODEL_LICENSE_EXPIRES = "model-license-exp-message"; } ``` Model license expiration message. Returns an expiration message string for the most recently loaded model, or `NULL` if no model is loaded. The returned string is of the form `"Model license expires on "`, or `NULL` for model license keys that do not expire. **Example:** ```c const char *expires; snsrGetString(s, SNSR_MODEL_LICENSE_EXPIRES, &expires); if (expires) fprintf(stderr, "%s\n", expires); ``` **Also see these related items:** [model-license-exp-date](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#model-license-exp-date), [model-license-exp-warn](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#model-license-exp-warn) ### model-license-exp-warn - runtime - string - read-only **C/C++** ```c #define SNSR_MODEL_LICENSE_WARNING "model-license-exp-warn" ``` **Java** ```java public class Snsr { public final static String MODEL_LICENSE_WARNING = "model-license-exp-warn"; } ``` Model license expiration warning message. This value is `NULL` for models with license keys that either do not expire, or that have an expiration date that is more than 60 days into the future. For license keys expiring in 60 days or fewer, the returned string will be of the form `"License will expire in 37 days."`. **Also see these related items:** [model-license-exp-date](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#model-license-exp-date), [model-license-exp-message](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#model-license-exp-message) ### model-name - runtime - string - read-write **C/C++** ```c #define SNSR_MODEL_NAME "model-name" ``` **Java** ```java public class Snsr { public final static String MODEL_NAME = "model-name"; } ``` Source model name. The name of the model file used to create: - ROM-able C code with [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save) and [SOURCE](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source). - A model in one of the supported embedded formats with [dsp-header-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-header-stream). This value is included in the comment header of the generated code, for information only. ### model:ids - runtime - string - read-write **C/C++** ```c #define SNSR_PREPARE_SUBSET_INIT "model:ids" ``` **Java** ```java public class Snsr { public final static String PREPARE_SUBSET_INIT = "model:ids"; } ``` Prepares a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) for generating custom initialization code. Set this value to `NULL` to enable [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) instrumentation. This is used by [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save) with [SUBSET_INIT](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_subset_init) to generate custom library initialization code (in C), which references only modules encountered during [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load). Linking against only a subset of available modules reduces executable size. This example will create a `custom-init.c` file. Add this to the build, and recompile with `-DSNSR_USE_SUBSET` to enable. The linked executable(s) will contain just the modules required to run `model-a.snsr` and `model-b.snsr`. **C/C++** **Example:** ```c SnsrSession s; snsrNew(&s); snsrSetString(s, SNSR_PREPARE_SUBSET_INIT, NULL); snsrLoad(s, snsrStreamFromFileName("model-a.snsr", "r")); snsrLoad(s, snsrStreamFromFileName("model-b.snsr", "r")); snsrSave(s, SNSR_FM_SUBSET_INIT, snsrStreamFromFileName("custom-init.c", "w")); snsrRelease(s); ``` **Also see these related items:** [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load), [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save), [SUBSET_INIT](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_subset_init) ### prune:enable - runtime - string - read-write - since [7.5.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.5.0) **C/C++** ```c #define SNSR_PRUNE_SETTINGS "prune:enable" ``` **Java** ```java public class Snsr { public final static String PRUNE_SETTINGS = "prune:enable"; } ``` Prepare a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) for pruning model settings Pruning unused settings from a model reduces peak RAM requirements. This is typically only useful on platforms where heap memory is constrained. Set `prune:enable` to `yes` to instrument model loading and running. This instrumentation: * Keeps track of which configuration settings the application accesses during model evaluation, * adds a list of these settings to the model upon saving, and * configures the model to prune settings not on this list from the runtime directly after loading. Set `prune:enable` to `no` to disable pruning. This is the default. **Note:** Pruned models do not contain enough information to be re-saved. **Also see these related items:** [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load), [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save) ### tag-identifier - runtime - string - read-write **C/C++** ```c #define SNSR_TAG_IDENTIFIER "tag-identifier" ``` **Java** ```java public class Snsr { public final static String TAG_IDENTIFIER = "tag-identifier"; } ``` Exported identifier in ROM C code. When text segment C code is created with [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save) and [SOURCE](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source), this setting specifies the name of the exported data structure. The value must start with an ASCII alphabetic character or `_`, and contain only alphanumerics and `_`; it must match regular expression `[A-Za-z_][A-Za-z0-9_]*` [epoch]: https://en.wikipedia.org/wiki/Unix_time "Unix time" [UTF-8]: https://en.wikipedia.org/wiki/UTF-8 *[API]: Application Programming Interface *[iff]: if, and only if *[LPCM]: Linear pulse-code modulation *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[NLU]: Natural Language Understanding model *[RAM]: Random Access Memory *[ROM]: Read-Only Memory, typically nonvolatile flash memory *[STT]: Speech To Text: transformers with language model and CTC decoding *[THF]: TrulyHandsfree, Sensory's wake word and command recognition technology *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[VAD]: Voice Activity Detector --- source_path: "api/setting-keys/values.md" canonical_url: "https://doc.sensory.com/tnl/7.8/api/setting-keys/values/" --- # Values These are string constants that define [task-types](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) used with [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require), or that identify template [slots](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot). ## enroll - value - string - read-only **C/C++** ```c #define SNSR_ENROLL "enroll" ``` **Java** ```java public class Snsr { public final static String ENROLL = "enroll"; } ``` Phrase spotter enrollment task type. **Also see these related items:** [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require), [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) ## feature - value - string - read-only - pre-release **C/C++** ```c #define SNSR_FEATURE "feature" ``` **Java** ```java public class Snsr { public final static String FEATURE = "feature"; } ``` Feature extractor task type. **Pre-release:** This is an experimental feature. Do not use unless recommended by Sensory. **Also see these related items:** [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require), [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) ## feature-lvcsr - value - string - read-only _(tnl)_ _(pre-release)_ **C/C++** ```c #define SNSR_FEATURE_LVCSR "feature-lvcsr" ``` **Java** ```java public class Snsr { public final static String FEATURE_LVCSR = "feature-lvcsr"; } ``` LVCSR recognizer from feature stream task type. **Pre-release:** This is an experimental feature. Do not use unless recommended by Sensory. **Also see these related items:** [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require), [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) ## feature-phrasespot - value - string - read-only - pre-release **C/C++** ```c #define SNSR_FEATURE_PHRASESPOT "feature-phrasespot" ``` **Java** ```java public class Snsr { public final static String FEATURE_PHRASESPOT = "feature-phrasespot"; } ``` Phrase spotter from feature stream task type. **Pre-release:** This is an experimental feature. Do not use unless recommended by Sensory. **Also see these related items:** [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require), [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) ## feature-vad - value - string - read-only - pre-release **C/C++** ```c #define SNSR_FEATURE_VAD "feature-vad" ``` **Java** ```java public class Snsr { public final static String FEATURE_VAD = "feature-vad"; } ``` VAD from feature stream task type. **Pre-release:** This is an experimental feature. Do not use unless recommended by Sensory. **Also see these related items:** [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require), [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) ## lvcsr - value - string - read-only - tnl **C/C++** ```c #define SNSR_LVCSR "lvcsr" ``` **Java** ```java public class Snsr { public final static String LVCSR = "lvcsr"; } ``` LVCSR and STT recognizer task type. **Also see these related items:** [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require), [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type), [LVCSR models](https://doc.sensory.com/tnl/7.8/models/index.md#lvcsr-models), [STT models](https://doc.sensory.com/tnl/7.8/models/index.md#stt-models) ## phrasespot - value - string - read-only **C/C++** ```c #define SNSR_PHRASESPOT "phrasespot" ``` **Java** ```java public class Snsr { public final static String PHRASESPOT = "phrasespot"; } ``` Phrase spotter task type. Also known as wake words, key word spotting, and spotted command sets. **Also see these related items:** [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require), [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type), [wake word models](https://doc.sensory.com/tnl/7.8/models/index.md#wake-word-models) ## phrasespot-vad - value - string - read-only **C/C++** ```c #define SNSR_PHRASESPOT_VAD "phrasespot-vad" ``` **Java** ```java public class Snsr { public final static String PHRASESPOT_VAD = "phrasespot-vad"; } ``` Phrase Spotter VAD task type. **Also see these related items:** [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require), [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type), [tpl-spot-vad](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad.md#tpl-spot-vad-type) ## vad - value - string - read-only **C/C++** ```c #define SNSR_VAD "vad" ``` **Java** ```java public class Snsr { public final static String VAD = "vad"; } ``` VAD task type. **Also see these related items:** [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require), [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type), [VAD models](https://doc.sensory.com/tnl/7.8/models/index.md#vad-models) *[API]: Application Programming Interface *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[VAD]: Voice Activity Detector --- source_path: "changes/index.md" canonical_url: "https://doc.sensory.com/tnl/7.8/changes/" --- # Version 7 changes (current) TrulyNatural version 7 introduced support for STT and is fully backwards compatible with [version 6](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6-changes) models and code. This library uses [semantic versioning][semver]. ## 7.8.0 (TBD) - **Added** - License key introspection: [LICENSE_INFO](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_license_info), [LICENSE_SUPPORT](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_license_support), [LICENSE_OVERRIDE_NOT_VALID](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). - [profile:samples](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#profilesamples). - [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) `-i` flag to support [batch processing](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#batch-processing). - LLM-friendly documentation Markdown bundle for coding agents and RAG pipelines. Each page is mirrored on the site at the same path as its source file—section roots as `

/index.md` beside `/index.html`, leaf pages as `/.md` beside `//index.html`—and the entry point is [llms.txt](https://doc.sensory.com/tnl/7.8/llms.txt): + [llms.txt](https://doc.sensory.com/tnl/7.8/llms.txt) — discoverable index following the [llmstxt.org](https://llmstxt.org) convention; lists every page with one-line summaries plus a `## Symbols` section deep-linking C/Java identifiers to their documenting headings. + [manifest.json](https://doc.sensory.com/tnl/7.8/manifest.json) — JSON index of every member with `path`, `source_path`, `bytes`, `title`, `canonical_url`, an optional H2/H3 outline on reference pages, and an optional ISO 8601 UTC `last_modified` so indexers can do incremental re-ingest. + [llms-full.txt](https://doc.sensory.com/tnl/7.8/llms-full.txt) — every page concatenated with `` separators for one-shot ingestion. + [agent-docs.zip](https://doc.sensory.com/tnl/7.8/agent-docs.zip) — same files packaged as a single archive for vendored or air-gapped use; agents with network access should crawl the loose mirror instead. - **Changed** - The [library-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-info) summary includes text for [LICENSE_SUPPORT](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_license_support). - [fromCode](https://doc.sensory.com/tnl/7.8/api/io.md#fromcode) checks that the `SnsrCodeModel` data were compiled with compatible `struct` packing. - [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) `-p` reports the real-time fraction required to run models in [template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) slots. - `spot-eval-batch` renamed to [snsr-eval-batch](https://doc.sensory.com/tnl/7.8/tools/snsr-eval-batch.md#snsr-eval-batch) with support for commands, LVCSR and STT models. - _(stt)_ [nlu-grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#nlu-grammar-stream) overrides machine-learned NLU only if it detects no NLU matches. - **Deprecated** - **Removed** - _lib/ios/libsnsr.a_, use XCFramework instead. - **Fixed** - Changes to [listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window) had no effect after the first call to [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler). - The documentation for [complete-only](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#complete-only) mistakenly noted that the default value was `0`. This had changed to `1` in [v6.20.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.20.0). - **Security** - On Windows, using filenames longer than 256 characters with [fromFileName](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename) or [fromAudioFile](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiofile) could cause out-of-bounds heap access. ## 7.7.0 (2026-01-24) - **Added** - Smart Wake Word option to gate a VAD with a wake word at the [start or at the end](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-opt-spot-vad-lvcsr.md#use-trailing-wake-word) of an utterance. + [wake-word-at-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#wake-word-at-end), [backlog-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backlog-interval) + [tpl-spot-vad-3.13.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad) + _(tnl)_ [tpl-spot-vad-lvcsr-3.23.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr) + _(tnl)_ [tpl-opt-spot-vad-lvcsr-1.28.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-opt-spot-vad-lvcsr) - Option to apply library license keys with [LICENSE](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_license) [configuration](https://doc.sensory.com/tnl/7.8/api/library-config.md#config-enum). + [LICENSE_OVERRIDE_NOT_ENABLED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_license_override_not_enabled), [LICENSE_OVERRIDE_NOT_SUPPORTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_license_override_not_supported). - Note that the [STT_SUPPORT](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_stt_support) [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) option requires a call to [new](https://doc.sensory.com/tnl/7.8/api/inference.md#new). - _(tnl)_ [lvcsr-build-enUS-12.13.1-5MB.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#lvcsr-build-enUS) with improved recognition accuracy and simplified out-of-grammar modeling. This model replaces both _lvcsr-build-enUS-2.7.3.snsr_ and _lvcsr-background-enUS-1.2.3.snsr_ included in the previous release. - **Changed** - _(stt)_ Improved STT model loading and initialization speed. - **Removed** - _tpl-spot-vad-3.10.0.snsr_ - _(tnl)_ _tpl-spot-vad-lvcsr-3.20.0.snsr_ - _(tnl)_ _tpl-opt-spot-vad-lvcsr-1.25.0.snsr_ - _(tnl)_ _lvcsr-build-enUS-2.7.3.snsr_ - _(tnl)_ _lvcsr-background-enUS-1.2.3.snsr_ - **Fixed** - _(tnl)_ Creating an LVCSR recognizer with a [grammar](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) that had a syntax error (such as unbalanced parentheses) _and_ included empty lines or comments at the start of the grammar could lead to a crash caused by de-referencing a `NULL` pointer. - _(stt)_ With [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval) `= 0` STT recognizers did not produce [recognition results](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) on short utterances. ## 7.6.1 (2025-11-25) - **Changed** - [Android examples](https://doc.sensory.com/tnl/7.8/api/sample/android/index.md#android-examples) build with Java 17 and later. - **Fixed** - Higher than expected CPU use in wake words and command sets. This addresses a regression introduced in [7.5.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.5.0). - [snsr-debug](https://doc.sensory.com/tnl/7.8/api/sample/android/snsr-debug.md#snsr-debug) mistakenly used [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-opt-spot-vad-lvcsr) and [stt-enUS-automotive-medium](https://doc.sensory.com/tnl/7.8/models/index.md#stt-enUS-automotive-medium) model versions from an earlier SDK release. - Some of the [C examples](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#c-examples) failed to build on Windows. - **Security** - [profile](https://doc.sensory.com/tnl/7.8/api/inference.md#profile) could access released memory if called on a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance where the model, or a filled [template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) slot, was replaced with another model at runtime. ## 7.6.0 (2025-09-15) - **Added** - Setting [`loop = 2`](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#loop) pins the [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-sequential) listening focus to the recognizer in slot `1`. - [tpl-spot-debug-1.5.1.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-debug) with support for NLU intents and entities. - [udt-universal-3.67.1.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#udt-universal) with improved accuracy. - [tpl-spot-vad-3.10.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad) with support for [include-wake-word-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-wake-word-audio). - [snsr-debug](https://doc.sensory.com/tnl/7.8/api/sample/android/snsr-debug.md#snsr-debug) Android sample replaces `spot-debug` and adds support for STT. - _(tnl)_ [tpl-spot-vad-lvcsr-3.20.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr) and [tpl-opt-spot-vad-lvcsr-1.25.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-opt-spot-vad-lvcsr) with support for [include-wake-word-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-wake-word-audio). - _(tnl)_ Documentation notes that [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score) values are not usable when [result-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#result-max) `> 1`. - _(stt)_ [stt-enUS-automotive-medium-2.3.15-pnc.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#stt-enUS-automotive-medium) + Support for [nlu-match-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-match-max). + Setting [stt-profile](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#stt-profile) does not change [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval). - _(stt)_ Support for STT on 64-bit iOS platforms: + _iPhoneOS_ on `arm64` and `arm64e`. + _iPhoneSimulator_ on `arm64` and `x86_64`. - **Changed** - Documentation system from [Doxygen][] to [Material for MkDocs][]. - `arm-linux-gnueabi` library requires GLIBC >= 2.17 instead of GLIBC >= 2.34 for improved compatibility. - _lib/\*/README\*md_ for the [supported target platforms](https://doc.sensory.com/tnl/7.8/reference/overview.md#supported-target-platforms) include the minimum required `GLIBC` version where relevant. - **Removed** - _tpl-spot-debug-1.5.0.snsr_ - _udt-universal-3.66.1.9.snsr_ - _tpl-spot-vad-3.9.0.snsr_ - `spot-debug` Android sample, see [snsr-debug](https://doc.sensory.com/tnl/7.8/api/sample/android/snsr-debug.md#snsr-debug) instead. - Know issues documentation page. - _(tnl)_ _tpl-spot-vad-lvcsr-3.19.0.snsr_ - _(tnl)_ _tpl-opt-spot-vad-lvcsr-1.24.snsr_ - _(stt)_ _stt-enUS-automotive-medium-2.3.13-pnc.snsr_ - **Fixed** - [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) could show incorrect license recognition or duration limits in the comments at the start of the header file it generates. - [allocPerf](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocperf) did not produce usable results when used with [allocStdlib](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocstdlib). - _(tnl)_ Incorrect [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), and [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score) results for a [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad-lvcsr.md#tpl-spot-vad-lvcsr-type) recognizer in [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot) `1` of [tpl-spot-concurrent](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-concurrent.md#tpl-spot-concurrent-type). - _(tnl)_ Using [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-sequential) in slot 0 of [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-opt-spot-vad-lvcsr) or [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr) could lead to warning messages on `stderr`. - _(tnl)_ [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) `-a` option failed when used with [class libraries](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-class-libraries). - _(stt)_ Bus error on 32-bit Arm platforms when using a model with machine-learned NLU or punctuation and capitalization support. This was caused by a [bug in ONNX](https://github.com/onnx/onnx/issues/6573) that resulted in an attempt to read `int64_t` values not aligned to 8 bytes. - **Security** - _(tnl)_ If [nlu-grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#nlu-grammar-stream) reduced the length of the phrase result (by using the `:` rewrite operator, for example) in an STT model with punctuation and capitalization support, an unterminated string could cause an out-of-bounds memory read. ## 7.5.0 (2025-06-12) - **Added** - [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) `-a`, `-q`, and `-u` flags. - [stt-support](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#stt-support), [thread-support](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#thread-support). - Support for loading parts of a model that resides in ROM onto the heap. This can improve inference speed when ROM is significantly slower than RAM. - Reduced peak RAM requirement on small platforms + [prune:enable](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#pruneenable) option to remove unused settings after a model's been loaded. + Reduced overhead in the session configuration store. - [fromProvider](https://doc.sensory.com/tnl/7.8/api/io.md#fromprovider) as an alias for `snsrStream_alloc()`. - [profile](https://doc.sensory.com/tnl/7.8/api/inference.md#profile) is available in the Java language binding. - Support for `armv7k` and `arm64_32` watchOS architectures. - [tpl-spot-concurrent-1.5.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-concurrent) with support for [^listen-begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-begin), [^listen-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-end), [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin), [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end), [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit), and [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence). - [tpl-spot-vad-3.9.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad) - _(tnl)_ [ram-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#ram-limit), [ac-prune-top-k](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#ac-prune-top-k). - _(tnl)_ Support for improved out-of-grammar detection (with better discrimination and lower RAM overhead) in [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) and [VoiceHub Pro](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub) models. - _(tnl)_ Support for [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) models that report recognition scores. - _(tnl)_ Templates with support for [domain](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#domain), [am-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#am-size), [lm-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#lm-size), [nlu-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-size), and [slm-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-size): + [tpl-opt-spot-vad-lvcsr-1.24.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-opt-spot-vad-lvcsr) + [tpl-spot-vad-lvcsr-3.19.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr) + [tpl-vad-lvcsr-3.17.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-vad-lvcsr) - _(tnl)_ Models updated to support [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score) setting: + _lvcsr-background-enUS-1.2.3.snsr_ + _lvcsr-build-enUS-2.7.3.snsr_ - _(stt)_ [domain](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#domain), [slm-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-size). - _(stt)_ [stt-enUS-automotive-medium-2.3.13-pnc.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#stt-enUS-automotive-medium) with support for [domain](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#domain) and [slm-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-size). This model includes a single language model, so [domain](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#domain) will return `NULL`. It does not include a generative language model either: [slm-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-size) is `0`. - **Changed** - Documentation available online. - [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) requires the `-o` flag to create output. - [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) prints scores with the `%g` format specifier. - [getDouble](https://doc.sensory.com/tnl/7.8/api/inference.md#getters), [setDouble](https://doc.sensory.com/tnl/7.8/api/inference.md#setters), [getInt](https://doc.sensory.com/tnl/7.8/api/inference.md#getters), and [setInt](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) support both double and integer settings, but will report [INCORRECT_SETTING_TYPE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_incorrect_setting_type) if a double value cannot be converted to an integer without loss of precision or overflow. - [getString](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) and [setString](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) support double and integer settings. - [set](https://doc.sensory.com/tnl/7.8/api/inference.md#set) no longer requires quotes for string arguments without embedded spaces. - [SOURCE](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source), [SOURCE_RAM](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source_ram), and [SOURCE_PRUNED](https://doc.sensory.com/tnl/7.8/api/inference.md#dataformat) create code that tags all model objects with preprocessor macro `SNSR_MODEL_ATTR`. Use this, for example, to specify the section in which the linker places these objects. - _sample/c/CMakeLists.txt_ + Builds `snsr-eval-subset`. + Installs the sample binaries in _sample/c/bin/_. - _sample/c/Makefile_ and _sample/c/CMakeLists.txt_ build the [live-spot-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot-stream.md#live-spot-streamc) example on macOS. - _util/gradlew_ uses Gradle 8.14, compatible with Java 21. - [Java examples](https://doc.sensory.com/tnl/7.8/api/sample/java/index.md#java-examples) use lambda expressions for event handlers and iterators. - [Enrolled wake word](https://doc.sensory.com/tnl/7.8/models/index.md#enroll-models) tasks no longer invoke [^pause](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#pause) and [^resume](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#resume) when [interactive](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#interactive) `== 0`. - _(tnl)_ [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-opt-spot-vad-lvcsr) and [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr) with [include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence) `= 1` no longer invoke the [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent), and [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) events if the VAD does not detect speech. The [^listen-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-end) directly follows the [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence) event. - _(tnl)_ [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) with live audio input will not run LVCSR or STT models that do not include a VAD component. Use the new `-a` flag to add [tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-vad-lvcsr) on the fly. - _(tnl)_ [complete-only](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#complete-only) `= 1` accepts results even if there's no trailing silence in the utterance. - _(stt)_ In STT models with punctuation and capitalization support, empty results are reported as an empty string instead of a single period. - **Removed** - _tpl-spot-concurrent-1.4.0.snsr_ - _tpl-spot-vad-3.8.0.snsr_ - _(tnl)_ _lvcsr-background-enUS-1.2.1.snsr_ - _(tnl)_ _lvcsr-build-enUS-2.7.0.snsr_ - _(tnl)_ _tpl-opt-spot-vad-lvcsr-1.20.0.snsr_ - _(tnl)_ _tpl-spot-vad-lvcsr-3.11.0.snsr_ - _(tnl)_ _tpl-vad-lvcsr-3.10.0.snsr_ - _(stt)_ _stt-enUS-automotive-medium-2.3.13.snsr_ - **Fixed** - Machine-learned VAD components detected the speech onset late on synthetic audio data with significant all-zero leading silence. - [oss-components](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#oss-components) always returned `NULL.` - _(tnl)_ In rare cases [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) NLU intent names could mistakenly include the first word of the NLU intent value. - _(tnl)_ In rare cases VoiceHub models that use [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) could misclassify in-domain intents as `background`. - _(tnl)_ Potentially reduced recognition accuracy in [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) models that use [ram-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#ram-limit) to constrain the Viterbi decoder. - **Security** - Deeply-nested templates with duplicate models (for example, combining the same spotter model with [tpl-spot-concurrent](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-concurrent), then combining the result with another [tpl-spot-concurrent](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-concurrent) and the same spotter model, three levels deep), could result in out-of-bounds memory access when releasing the session. ## 7.4.1 (2025-03-13) - **Fixed** - _(stt)_ Using [custom-vocab](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#custom-vocab) to map multi-word sequences could result in missed NLU entities. ## 7.4.0 (2025-01-22) - **Added** - Java support on _x86_64-windows-msvc._ - [SOURCE_RAM](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source_ram) and [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) `-C` option. - Spotter template modes with new settings [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point) and [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms): + [tpl-spot-debug-1.5.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-debug) + [tpl-spot-vad-3.8.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad) + [tpl-spot-sequential-1.5.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-sequential) - Support for Smart Wake Words. On a near-miss false reject, these models switch to a more accepting operating point for a limited duration to make it more likely that the model will accept a repeated wake word utterance. Enable this feature (on wake word models that support it) by setting [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point). Adjust the duration of the low false-reject listening window with [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms). - [spot-voicegenie-enUS-6.5.1-m.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#spot-voicegenie-enUS) with support for [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point) and [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms). - Compatibility with 2025 [VoiceHub Pro](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub) wake words and command sets. - [VERSION_CMAKE](https://doc.sensory.com/tnl/7.8/api/constants.md#version_cmake). - _(tnl)_ [tpl-opt-spot-vad-lvcsr-1.20.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-opt-spot-vad-lvcsr) supports changing VAD settings [backoff](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backoff), [hold-over](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#hold-over), [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence), [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording), [trailing-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#trailing-silence), and [include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence). Adds [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator), [^slm-start](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-start), [^slm-result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result-partial), [^slm-result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result), [slm-enabled](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-enabled), [slm-turn-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-turn-limit), [stt-profile](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#stt-profile), [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point), and [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms). - _(tnl)_ VAD template models with new settings [^slm-start](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-start), [^slm-result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result-partial), [^slm-result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result), [slm-enabled](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-enabled), [slm-turn-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-turn-limit), [stt-profile](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#stt-profile), [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point), and [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms): + [tpl-spot-vad-lvcsr-3.15.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr) + [tpl-vad-lvcsr-3.14.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-vad-lvcsr) - _(stt)_ [stt-profile](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#stt-profile). - _(stt)_ Experimental support for generative language models. New settings: [^slm-start](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-start), [^slm-result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result-partial), [^slm-result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result), [slm-enabled](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-enabled), and [slm-turn-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slm-turn-limit). - _(stt)_ _stt-enUS-automotive-medium-2.3.13.snsr_ + Results include capitalization and punctuation. + Supports [stt-profile](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#stt-profile). - **Changed** - Android JNI shared libraries export only TrulyNatural function names. This significantly reduces the chances of symbol clashes in applications that use third-party libraries that depend on the same OSS modules as the TrulyNatural SDK. - Android JNI libraries built with NDK r27c and [flexible page size support][]. - Improved compatibility with older Android releases, support for [API level 21][api-levels] and later. - _SnsrLibrary.cmake_ removes unused functions and data from target executables (`-ffunction-sections -fdata-sections`) - DSP library (for creating embedded spotter models) version 8.5.0. - Toolchain updates: + _arm-linux-gnueabi_ built with gcc 13.2.0. + _arm-linux-gnueabihf_ built with gcc 13.3.1. + _i686-linux-gnu_ built with gcc 13.2.0. - On Windows, [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) sets the console code page to `UTF-8.` - If application code used [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) and did not call [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop) before releasing the model, the call to [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) invoked all pending event handlers. It now ignores these. - [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop) completes even if the session is in an error state. - _(tnl)_ No [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) for empty hypotheses. - _(stt)_ Support Windows `\r\n` line termination as entry separators in [custom-vocab](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#custom-vocab). - _(stt)_ Removed the 1000-entry limit for [custom-vocab](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#custom-vocab). Please note that using such large custom vocabularies is frequently counter-productive. Consider contacting your [Sensory Sales](https://doc.sensory.com/tnl/7.8/contact.md#contact) representative to discuss creating a domain-specific recognizer instead. - _(stt)_ Improved [custom-vocab](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#custom-vocab) behavior in character-based languages such as Mandarin Chinese. - _(stt)_ STT models start fewer threads. - **Deprecated** - [threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#threshold). - **Removed** - _spot-voicegenie-enUS-6.5.0-m.snsr_ - _tpl-spot-debug-1.4.0.snsr_ - _tpl-spot-sequential-1.4.0.snsr_ - _tpl-spot-vad-3.7.0.snsr_ - _tpl-spot-dynop-1.4.0.snsr_ - _(tnl)_ _tpl-opt-spot-vad-lvcsr-1.12.0.snsr_ - _(tnl)_ _tpl-spot-vad-lvcsr-3.11.0.snsr_ - _(tnl)_ _tpl-vad-lvcsr-3.10.0.snsr_ - _(stt)_ _stt-enUS-automotive-small_medium-2.2.13-BBB-ff.snsr_ - **Fixed** - With [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit) `> 0`, [reset](https://doc.sensory.com/tnl/7.8/api/inference.md#reset) did not flush the push backlog buffer enabled with [push-buffer-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-buffer-size). - Low memory use VoiceHub Large Vocabulary Project models could fail to run if settings (such as [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point)) were changed after registering event handlers. - Reading settings from models built from deeply nested templates could mistakenly report [VALUE_NOT_SET](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). - _(tnl)_ [search.frame-nota](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#searchframe-nota) was ignored for [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) when used with lightweight NLU. - **Security** - If application code using the C API used [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), and a result handler called [forEach](https://doc.sensory.com/tnl/7.8/api/inference.md#foreach), and that handler was invoked by [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) because the session was released without calling [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop) first, then a double-free and access of invalid heap memory could occur. - _(tnl)_ Out-of-bounds memory access could occur if [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-opt-spot-vad-lvcsr) was used with `0.include-leading-silence = 1`. ## 7.3.0 (2024-07-29) - **Added** - New FAQ section: [How do I take action on an NLU result?](https://doc.sensory.com/tnl/7.8/faq.md#lvcsr-nlu-action) - Support for adding this SDK to projects that use CMake. See [C examples](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#examples-cmake). - Real-time clock implementation for Windows, enables [profile:real-time](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#profilereal-time). - Support for multi-phrase spotter models with lower false accept rates. - _arm-none-eabi_ library with NEON built with gcc 13.3.1. - _(tnl)_ VAD template models with settings [backoff](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backoff) and [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording) optimized for STT. The defaults are now 300 ms for audio backoff, and 60 seconds for the maximum recording duration. + _tpl-opt-spot-vad-lvcsr-1.12.0.snsr_ + _tpl-spot-vad-lvcsr-3.11.0.snsr_ + _tpl-vad-lvcsr-3.10.0.snsr_ - _(stt)_ Improved STT recognition speed and accuracy, and reduced [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) and [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent) latency when used with a VAD. - _(stt)_ STT support for _arm-linux-gnueabihf,_ _aarch64-linux-gnu,_ and _x86_64-windows-msvc._ - _(stt)_ _stt-enUS-automotive-small_medium-2.2.13-BBB-ff.snsr_ + 100 MiB total size compared to 299 MiB in previous version. + Improved NLU inference speed. + Improved accuracy. - **Changed** - _arm-linux-gnueabihf_ and _aarch64-linux-gnu_ libraries built with gcc 10.3.1. - _(tnl)_ Optimized machine-learned NLU models. On average these now run about ten times faster. - **Removed** - Windows ports: x86-windows-2008, x86-windows-2015, x86_64-windows-2008, x86_64-windows-2015, x86_64-windows-mingw. - _arm-buildroot-linux-uclibcgnueabihf_ library. - _arm-ca7-linux-gnueabihf_ library. - _(tnl)_ VAD template models: + _tpl-opt-spot-vad-lvcsr-1.11.0.snsr_ + _tpl-spot-vad-lvcsr-3.10.0.snsr_ + _tpl-vad-lvcsr-3.9.0.snsr_ - _(stt)_ _stt-enUS-automotive-small_medium-2.0.8-BBB-ff.snsr_ - **Fixed** - Certain low false-accept spotter models reported an internal validation error when used with _tpl-spot-sequential-1.4.0.snsr_ - [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) `-c` produced incorrect code output for recent low false-accept models. - The iOS sample app mistakenly embedded _snsr.xcframework,_ leading to TestFlight rejection due to asset validation errors. - The TrulyNatural SDK linked against `-landroid,` making it incompatible with the [Vendor Native Development Kit][]. - _(stt)_ Duplicate entities and typographic errors in the documentation for _stt-enUS-automotive-small_medium-2.2.13-BBB-ff.snsr_ - **Security** - _(stt)_ NLU models could cause out-of-bounds memory access on very long (hundreds of words) recognition results. ## 7.2.0 (2024-04-11) - **Added** - [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) `-p` option shows an estimate of the CPU processing capacity required to run a model in real-time. - [profile:real-time](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#profilereal-time). - _(tnl)_ [nlu-intent-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-score), [nlu-entity-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-score), and [nlu-slot-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-score). - _(tnl)_ Models updated to support NLU score and [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score) settings: + [tpl-opt-spot-vad-lvcsr-1.11.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-opt-spot-vad-lvcsr) + [tpl-spot-vad-lvcsr-3.10.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr) + [tpl-vad-lvcsr-3.9.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-vad-lvcsr) - _(stt)_ [am-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#am-size), [lm-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#lm-size), [nlu-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-size). - _(stt)_ _stt-enUS-automotive-small_medium-2.0.8-BBB-ff.snsr_ + Improved recognition accuracy compared to _stt-v2-enUS-automotive-0.2.11-BT-400ms.snsr_ + Adjusts model evaluation interval to match [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval). - **Changed** - [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) ignores [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit). - _(tnl)_ `snsr-eval` `-lll` does not show [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent) or [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) results. - _(tnl)_ [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) shows NLU intent, entity, and slot scores. - _(stt)_ STT models use [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval) to set the model evaluation interval. The larger this interval the lower the average CPU use. - **Removed** - _(tnl)_ Models updated to support NLU score settings: + _tpl-opt-spot-vad-lvcsr-1.9.0.snsr_ + _tpl-spot-vad-lvcsr-3.8.0.snsr_ + _tpl-vad-lvcsr-3.8.0.snsr_ + _tpl-spot-lvcsr-1.5.0.snsr_ (Use [tpl-spot-vad-lvcsr-3.10.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr) instead.) - _(stt)_ _stt-v2-enUS-automotive-0.2.11-BT-400ms.snsr_ - **Fixed** - [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) now returns [LIBRARY_TOO_OLD](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) when attempting to load a model that uses features it does not support. ## 7.1.1 (2024-02-13) - **Fixed** - Linking against the Android static libraries could suppress the output of calls to `__android_log_print(),` `__android_log_vprint(),` and `__android_log_write()` in the entire application. - The AAR file for Android once again links against `-llog.` - _(tnl)_ [tpl-spot-vad-lvcsr-3.8.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr) would keep listening for LVCSR audio if enough silence after the wake word lead to [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence). + This happened only for LVCSR recognizers (including those made with [VoiceHub](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub)) and did not affect STT ones. + Regression from 7.0.0. ## 7.1.0 (2024-01-11) - **Added** - _(tnl)_ Simplified NLU API + Reduces NLU slot hierarchy to just two levels. + Provides direct access to top-level NLU slots as "intents" and child slots as "entities". + Does not support [nlu-match-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-match-max) `>` `1.` + Does not replace the existing NLU slot API. + See [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent), [nlu-intent-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-name), [nlu-intent-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-value), [nlu-entity-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-entity-iterator), [nlu-entity-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-count), [nlu-entity-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-name), and [nlu-entity-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-value). - _(tnl)_ Models updated to support simplified NLU API: + _lvcsr-background-enUS-1.2.1.snsr_ + _lvcsr-build-enUS-2.7.0.snsr_ + _tpl-opt-spot-vad-lvcsr-1.9.0.snsr_ + _tpl-spot-lvcsr-1.5.0.snsr_ + _tpl-spot-vad-lvcsr-3.8.0.snsr_ - _(stt)_ Support for machine-learned NLU intent and entity classifiers. - _(stt)_ [custom-vocab](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#custom-vocab) - _(stt)_ _stt-v2-enUS-automotive-0.2.11-BT-400ms.snsr_ - **Changed** - AAR file for Android is no longer linked against `-landroid` and `-llog.` This allows it to be used in an AOSP system image. - **Removed** - Energy-only VAD models superseded by machine-learned versions: + _tpl-spot-vad-2.4.0.snsr_ + _tpl-spot-vad-2.0.1.snsr_ + _(tnl)_ _tpl-spot-vad-lvcsr-2.4.0.snsr_ + _(tnl)_ _tpl-vad-lvcsr-2.5.0.snsr_ - _(tnl)_ Models updated to support simplified NLU API: + _lvcsr-background-enUS-1.1.0.snsr_ + _lvcsr-build-enUS-2.6.0.snsr_ + _tpl-opt-spot-vad-lvcsr-1.8.0.snsr_ + _tpl-spot-lvcsr-1.4.0.snsr_ + _tpl-spot-vad-lvcsr-3.7.0.snsr_ + _tpl-vad-lvcsr-3.7.0.snsr_ - _(stt)_ _stt-v1-en-1.0.1-400ms.snsr_ - **Fixed** - [VAD models](https://doc.sensory.com/tnl/7.8/models/index.md#vad-models) models ignored the [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording) setting. - _(tnl)_ [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-opt-spot-vad-lvcsr) did not produce a [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) for [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot) `=` [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0) if [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0).[include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence) was set to `1` and a [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence) timeout occurred. - _(tnl)_ LVCSR models used in a [VAD](https://doc.sensory.com/tnl/7.8/models/index.md#vad-models) template would stop producing [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) callbacks if the VAD reported [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit). STT models were not affected. ## 7.0.0 (2023-11-20) - **Added** - [CONFIG_PRUNED](https://doc.sensory.com/tnl/7.8/api/inference.md#dataformat) and [SOURCE_PRUNED](https://doc.sensory.com/tnl/7.8/api/inference.md#dataformat) reduce the size of serialized models by removing configuration options such as unused [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) values. - [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) `-p` option reduces [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot) model sizes by removing operating points other than the currently selected [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point). - _(stt)_ STT support with improved accuracy suitable for command-and-control and dictation tasks. + **This initial release includes STT support on Android, macOS, and x86_64-linux only.** + Includes Open Source modules, see [open source licenses](https://doc.sensory.com/tnl/7.8/licenses/oss.md#open-source-licenses). + Requires linking against a C++ runtime, see [Integrate with your build](https://doc.sensory.com/tnl/7.8/api/build-system.md#integrate-with-your-build). + Using STT models do not require any API changes. These are drop-in replacements for older LVCSR models on supported platforms. + STT recognition models - _stt-v1-en-1.0.1-400ms.snsr_ - Contact your [Sensory Sales](https://doc.sensory.com/tnl/7.8/contact.md#contact) representative for additional languages. + New settings: [oss-components](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#oss-components), [STT_SUPPORT](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_stt_support). - **Changed** - The deprecated [delay](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#delay) setting is read-only. - DSP library (for creating embedded spotter models) version 7.4.0. - _(tnl)_ The effects of `:` terminal rewrites @b are now visible in [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) values. - _(tnl)_ The lightweight NLU processor scoring algorithm no longer considers `:inserted` and `removed:` words when ranking result parses. This potentially changes the primary NLU result, or the order in which NLU results are presented when [nlu-match-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-match-max) `> 1`, for grammars that use the `:` rewrite feature to better match expectations. - _(tnl)_ If the time required to compute a partial LVCSR result exceeds the [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit), the [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) callback does not happen. - _(tnl)_ The [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) grammars support the literal use of special tokens by escaping them with a backslash. - **Deprecated** - Lightweight VAD. Use a [VAD model](https://doc.sensory.com/tnl/7.8/models/index.md#vad-models) instead. - **Removed** - _(tnl)_ References to the `<-` slot assignment operator in [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition). This had been a symbol reserved for internal use only. - _(tnl)_ _lvcsr-broad-enUS-3.1.0-t5.snsr_ - **Fixed** - Machine-learned [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type) models could unexpectedly report an error that `from-index (...) must be >= first-index (...)` - A subset of spotter models showed increased false accept rates when used with [task templates](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type). - _(tnl)_ [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-opt-spot-vad-lvcsr) mistakenly invoked [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence) and [^listen-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-end) multiple times at end-of-stream if [0.include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence) was set to `1`. - _(tnl)_ [tpl-spot-concurrent](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-concurrent) with a spotter model in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0) and an LVCSR model (gated by a VAD, or spotter and VAD) in slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1) would mistakenly return [nlu-slot-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-name) and [nlu-slot-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-value) values as `NULL.` - _(tnl)_ [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) could still occur even if [complete-only](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#complete-only) suppressed the recognition result. - _(tnl)_ [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) with [classes](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-classes) could fail with a segmentation fault when attempting to build a recognizer with too many class references. - **Security** - This sequence of operations could lead to [getString](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) returning an unterminated string: + Use [setStream](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) to set a configuration value to a sequence of bytes that does not include `\0.` + Save the model to persistent storage. + Load the modified model from persistent storage. + Access the configuration value with [getString](https://doc.sensory.com/tnl/7.8/api/inference.md#getters). - In the Java language binding [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory) and [fromString](https://doc.sensory.com/tnl/7.8/api/io.md#fromstring) could potentially access the underlying `byte[]` memory after it was garbage-collected. [api-levels]: https://en.wikipedia.org/wiki/Android_version_history "Android version history and API levels" [Doxygen]: https://doxygen.nl/ "Code Documentation. Automated." [flexible page size support]: https://developer.android.com/guide/practices/page-sizes "Support 16 KB page sizes on Android" [Material for MkDocs]: https://squidfunk.github.io/mkdocs-material/ "Documentation system" [semver]: http://semver.org/ "Semantic versioning specification" [Vendor Native Development Kit]: https://source.android.com/docs/core/architecture/vndk "Android Vendor Native Development Kit" *[API]: Application Programming Interface *[FR]: False Reject: the recognizer did not trigger when the target phrase was spoken *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[NLU]: Natural Language Understanding model *[OSS]: Open-source software *[PNC]: Punctuation and Capitalization, an STT model variant that emits cased text with punctuation *[RAM]: Random Access Memory *[ROM]: Read-Only Memory, typically nonvolatile flash memory *[SDK]: Software Development Kit *[SLM]: Generative Small Language Model *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets *[VAD]: Voice Activity Detector --- source_path: "changes/version-5.md" canonical_url: "https://doc.sensory.com/tnl/7.8/changes/version-5/" --- # Version 5 beta changes **Tip:** Looking for the latest changes? See [Version 7 changes](https://doc.sensory.com/tnl/7.8/changes/index.md#v7-changes). TrulyHandsfree version 5 introduced a new API and model file format, neither of which were backwards compatible with TrulyHandsfree version 4. The end of this beta release cycle resulted in stable release [v6.0.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.0.0). ## 5.0.0-beta.18 (2018-03-09) - **Added** - Live audio support in [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) for macOS and iOS. - [snsr-log-split](https://doc.sensory.com/tnl/7.8/tools/snsr-log-split.md#snsr-log-split) computes average throughput and real-time factor. - **Fixed** - User-Defined Trigger enrollments with a low phrase quality were rejected without providing sensible feedback. ## 5.0.0-beta.17 (2018-02-23) - **Added** - Spotter debug logging: + Task model: [tpl-spot-debug](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-debug.md#tpl-spot-debug-type). + [snsr-log-split](https://doc.sensory.com/tnl/7.8/tools/snsr-log-split.md#snsr-log-split) utility. + [faq](https://doc.sensory.com/tnl/7.8/faq.md#faq) answer for [How do I diagnose wake word audio issues?](https://doc.sensory.com/tnl/7.8/faq.md#debug-wake-word-audio). - [audio-check](https://doc.sensory.com/tnl/7.8/tools/audio-check.md#audio-check) utility. - Android `SpotDebug` sample app. See [Android examples](https://doc.sensory.com/tnl/7.8/api/sample/android/index.md#android-examples). - Example Android [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) implementation `sample/android/misc/SnsrStreamAudioDeviceAndroid.java` - Example Java [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) implementation `sample/java/misc/SnsrStreamAudioDeviceGeneric.java` - iOS C library. Note that [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) does not, as yet, support live audio recording on iOS. - **Changed** - DSP library (for creating embedded spotter models) version 4.4.2. - **Fixed** - For Enrolled Fixed Triggers, incorrect enrollment phrases were reported once all enrollment recordings were complete. This error is now reported immediately after the failed recording. - Android [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) can throw an `IllegalStateException` if the underlying audio device is busy. Now reported as an `IOException`. - The Android sample `Enroll.onResume()` method mistakenly returned `SnsrRC.ERROR` instead of `SnsrRC.STREAM` if `mAudio.open()` failed. ## 5.0.0-beta.16 (2018-01-25) - **Changed** - Improved v4 fixed trigger false reject performance when the spotted phrase is repeated multiple times in quick succession. - Android libraries built with NDK 16. - **Fixed** - Misleading detailed error message when attempting to load an incompatible spotter into a template. ## 5.0.0-beta.15 (2017-12-08) - **Added** - Task model _vad-energy-1.0.3.snsr_ (removed in 5.0.0-beta.13) restored. - **Changed** - DSP library (for creating embedded spotter models) version 4.4.1. - **Fixed** - Cannot load a model created using the `tpl-spot-concurrent-1.0.3.snsr` template into the `tpl-spot-vad-1.0.3.snsr` template. - [noise-energy](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#noise-energy), [signal-energy](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#signal-energy), [snr](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#snr) are no longer updated once approximately `1000` seconds of audio have been processed. - The md5 and sha1 hashes for licensed models and libraries in the embedded Maven repository (_m2repository/_) do not match the actual files. - _spot-eval_ command-line tool does not flush `stdout` frequently enough. - _spot-eval_ not compatible with spotter model versions `0.5.0` through `0.7.0.` ## 5.0.0-beta.14 (2017-11-01) - **Fixed** - _spot-eval_ command-line tool failed on models from earlier releases. ## 5.0.0-beta.13 (2017-10-31) - **Added** - New [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) command-line utility. - Support for [task templates](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type). This allows, for example, running two disparate phrase spotters at the same time, as a single spotter model. - [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) settings: [^listen-begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-begin), [^listen-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-end). - [faq](https://doc.sensory.com/tnl/7.8/faq.md#faq) documentation section. - New task models: + _eft-hbg-enUS-23.0.0.3.snsr_ + _spot-music-enUS-1.0.3-m.snsr_ + _tpl-spot-concurrent-1.0.3.snsr_ + _tpl-spot-sequential-1.0.3.snsr_ + _tpl-spot-vad-1.0.3.snsr_ - **Changed** - _spot-eval_ supports [phrase spotter with VAD](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad.md#tpl-spot-vad-type) models. - [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) uses only the tail portion of the task model file path to determine the output file prefix. - Renamed Java package from `com.sensory.speech` to `com.sensory.speech.snsr`. - Renamed `SnsrStream.Plugin` to `SnsrStream.Provider`. - Most `SnsrStream.Provider` methods now throw `IOException`. - [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudiojava) sample uses _tpl-spot-vad-1.0.3.snsr_ template for voice audio detection. - Support reading of RIFF wave files with padded format chunks (for example, those using a non-standard 48-byte header.) - Updated task models: + _spot-hbg-enUS-1.2.3-m.snsr_ + _udt-enUS-12.0.10.3.snsr_ + _udt-enUS-5.1.1.3.snsr_ - _push-spot.c_ sample includes VAD audio processing. - **Removed** - Task model: + _vad-energy-1.0.3.snsr_, use _tpl-spot-vad-1.0.3.snsr_ template instead. - **Fixed** - [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator) did not return all operating points. Also apparent when running `#!sh spot-eval -v -v -t spot-hbg-enUS-1.2.3-m.snsr` - [setStream](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) failed to set [<-audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-pcm-out) if the output stream was both readable and writable. - Java [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) method signatures did not match the documentation. These returned `void` instead of `long`. - Java [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory) and [fromString](https://doc.sensory.com/tnl/7.8/api/io.md#fromstring) streams produced incorrect data for large source stores. - Java writable [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory) streams did not modify the `byte[]` store. - Java [print](https://doc.sensory.com/tnl/7.8/api/io.md#stream-print) crashed with an assertion. - Java [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) methods [copy](https://doc.sensory.com/tnl/7.8/api/io.md#stream-copy), [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open), [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) [skip](https://doc.sensory.com/tnl/7.8/api/io.md#stream-skip), [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write), and [print](https://doc.sensory.com/tnl/7.8/api/io.md#stream-print) did not throw expected `IOException`s. - **Security** - Java [fromMemory](https://doc.sensory.com/tnl/7.8/api/io.md#frommemory) and [fromString](https://doc.sensory.com/tnl/7.8/api/io.md#fromstring) streams could access memory that was no longer valid. ## 5.0.0-beta.12 (2017-09-05) - **Added** - [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type) with: + Settings: [backoff](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backoff), [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin), [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end), [hold-over](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#hold-over), [include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence), [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence), [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit), [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording), [pass-through](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#pass-through), [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence), [skip-to-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#skip-to-ms), [skip-to-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#skip-to-sample), [trailing-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#trailing-silence), [vad](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#vad) + Stream: [<-audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-pcm-out). - The 64-bit Windows installer includes 32-bit libraries. + For MSVC 2008-2013 use _lib/x86-windows-2008/_ + For MSVC 2015 and later, use _lib/x86-windows-2015/_ - **Changed** - Documentation for [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream), [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample). - [live-segment.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-segment.md#live-segmentc) now uses the new VAD. - [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudiojava) now use the new VAD. - Noted `-24` [dBFS][] peak-to-peak audio recommendation. - **Fixed** - [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator) did not return all operating points. Also apparent when running `#!sh spot-eval -v -v -t spot-hbg-enUS-1.2.3-m.snsr` ## 5.0.0-beta.11 (2017-06-29) - **Added** - [VERSION_DSP](https://doc.sensory.com/tnl/7.8/api/constants.md#version_dsp). - [confidence-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#confidence-score). - Support for modular feature extractors. - Microsoft Visual Studio version-specific libraries and build files: + For MSVC 2008-2013 use _lib/x86_64-windows-2008/_ and _sample/c/msvc-2008/_ + For MSVC 2015 and later, use _lib/x86_64-windows-2015/_ and _sample/c/msvc-2015/_ - **Changed** - [library-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-info) includes [VERSION_DSP](https://doc.sensory.com/tnl/7.8/api/constants.md#version_dsp). - _spot-eval_ shows spotter [confidence scores](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#confidence-score), where available. - **Fixed** - Mistaken spots when the input audio stream ends. The work-around in previous beta was to set [auto-flush](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#auto-flush) to `0`. - [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) did not report output errors. ## 5.0.0-beta.10.3 (2017-06-22) - **Added** - `mipsel-openwrt-linux-musl` support. ## 5.0.0-beta.10.2 (2017-05-13) - **Added** - [auto-flush](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#auto-flush) runtime library setting. - _push-spot.c_ sample. ## 5.0.0-beta.10.1 (2017-05-02) - **Added** - `arm-ca7-linux-gnueabihf` support. - **Changed** - The `arm-linux-gnueabi` library uses softfp `float-abi` (soft, previously.) This enables NEON optimization. - `x86_64-linux-gnu` library is built with gcc 4.8 for better compatibility with older Linux distributions. ## 5.0.0-beta.10 (2017-04-20) - **Added** - Support for phrase spotters with multiple operating points in a single model. - [Wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) settings: [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point), [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator), [available-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#available-point). - [SnsrEnrollmentTest.java](https://doc.sensory.com/tnl/7.8/api/sample/java/SnsrEnrollmentTest.md#snsrenrollmenttestjava) enrollment unit test sample. - **Changed** - The `arm-linux-gnueabi` library now targets the ARMv7-a instruction set. - **Fixed** - [C examples](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#c-examples) `make` `test` fails when the SDK is installed on a path containing spaces. - Installer on Windows failed on paths containing unicode characters. ## 5.0.0-beta.9.1 (2017-04-11) - **Added** - `mipsel-buildroot-linux-uclibc` support. ## 5.0.0-beta.9 (2017-03-20) - **Added** - [Wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) result settings: [noise-energy](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#noise-energy), [signal-energy](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#signal-energy) and [snr](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#snr). - [LIBRARY_TOO_OLD](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). - [Wake word enrollment](https://doc.sensory.com/tnl/7.8/models/types/enroll.md#enroll-type) support for saving adapted enrollment contexts. - [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), [re-adapt](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#re-adapt). - [spot-enroll](https://doc.sensory.com/tnl/7.8/tools/spot-enroll.md#spot-enroll) has an `-a` option for saving adapted enrollment contexts. - **Changed** - `SNSR_TECH_LEVEL`. - **Task file format.** Earlier betas are not compatible with the models included in this release. - [C examples](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#c-examples) Makefile uses adapted enrollment context in the `test-enroll-1` target. - [copy](https://doc.sensory.com/tnl/7.8/api/io.md#stream-copy), [getDelim](https://doc.sensory.com/tnl/7.8/api/io.md#stream-getDelim), [print](https://doc.sensory.com/tnl/7.8/api/io.md#stream-print), [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read), [skip](https://doc.sensory.com/tnl/7.8/api/io.md#stream-skip), and [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) open the SnsrStream if it is not already open. Previous behavior was to return a [NOT_OPEN](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) error or to throw a Java `IOException`. - Java [copy](https://doc.sensory.com/tnl/7.8/api/io.md#stream-copy), [getDelim](https://doc.sensory.com/tnl/7.8/api/io.md#stream-getDelim), [print](https://doc.sensory.com/tnl/7.8/api/io.md#stream-print), [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read), [skip](https://doc.sensory.com/tnl/7.8/api/io.md#stream-skip), and [write](https://doc.sensory.com/tnl/7.8/api/io.md#stream-write) marked as `#!java throws IOException`. - **Fixed** - Enrollment failures due to low SNR not reported. ## 5.0.0-beta.8.1 (2017-02-17) - **Added** - `arm-buildroot-linux-uclibcgnueabihf` support. ## 5.0.0-beta.8 (2017-02-10) - **Added** - `SNSR_TECH_LEVEL`. - Java `SnsrStream.fromPlugin()`. - [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudiojava) in [Java examples](https://doc.sensory.com/tnl/7.8/api/sample/java/index.md#java-examples) shows how to capture audio following a spotted phrase. - [live-segment.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-segment.md#live-segmentc) example shows how to capture audio following a spotted phrase. - **Changed** - Changelog format based on [Keep a Changelog](http://keepachangelog.com/). - [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) type changed from `int` to `double` - potential incompatibility with earlier betas. - [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) on Linux: + Uses larger capture buffer. + Tries to recover from transient capture errors. - [new](https://doc.sensory.com/tnl/7.8/api/inference.md#new) is a macro that checks [VERSION](https://doc.sensory.com/tnl/7.8/api/constants.md#version) found in `snsr.h`. This has to match the version of binary archive library, or initialization will fail with [LIBRARY_HEADER](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). - **Fixed** - On 32-bit CPUs, [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) mistakenly returns [ITERATION_LIMIT](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) after processing 74.5 hours of audio without spotted phrases. - Spurious [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof) reports from [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) on Linux. - Java [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) method failed to throw any `Exceptions` on failure. This lead to misleading `Exception` messages produced by later library calls (e.g. `task type not found`). - [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) and [forEach](https://doc.sensory.com/tnl/7.8/api/inference.md#foreach) mistakenly reported certain callback-generated error codes, such as [INTERRUPTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), as the generic [ERROR](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). ## 5.0.0-beta.7 (2017-01-12) - **Added** - [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) supports live capture from Windows MME devices. This SnsrStream implementation is included in the C sample code as [wmme-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/wmme-stream.md#wmme-streamc). - Support for building the [C examples](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#c-examples) code: + with [CMake][] on Linux, macOS and Windows. + with Microsoft Visual C++ on Windows. - [enrollUDT.java](https://doc.sensory.com/tnl/7.8/api/sample/java/enrollUDT.md#enrolludtjava) supports enrollments for multiple users/phrases. - **Fixed** - Spotter alignment timestamps ([begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample)) wrapped around to `0` after approximately `1000` seconds. ## 5.0.0-beta.6 (2016-12-16) - **Added** - Support for combined fixed, enrolled fixed, and user-defined triggers. - [Wake word enrollment](https://doc.sensory.com/tnl/7.8/models/types/enroll.md#enroll-type) configuration setting, [enrollment-task-index](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#enrollment-task-index). - Improved Java [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) module documentation. - **Changed** - Renamed _live-spot-sample.c_ to [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spotc). ## 5.0.0-beta.5 (2016-12-02) - **Fixed** - Updated UDT model _udt-enUS-5.1.1.1.snsr._ - Linux [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) uses interleaved ALSA capture for improved compatiblity with PulseAudio. ## 5.0.0-beta.4 (2016-11-21) - **Added** - Support enrollments with trailing context to improve performance. + Configuration settings: [req-enroll](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#req-enroll), [ctx-enroll](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#ctx-enroll), [add-context](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#add-context). + Updated [wake word enrollment](https://doc.sensory.com/tnl/7.8/models/types/enroll.md#enroll-type). - Option to include enrollment audio in enrollment contexts. + Configuration setting: [save-enroll-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#save-enroll-audio). + Iterator: [enrollment-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#enrollment-iterator). + Result settings: [enrollment-id](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#enrollment-id), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample). + Runtime settings: [audio-stream-first](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-first), [audio-stream-last](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-last), [audio-stream-from](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-stream-from), [audio-stream-to](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-stream-to). - [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) supports high latency audio, with reduced CPU overhead. This is the now the default behavior. - [library-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-info) setting. - _udt-enUS-5.1.1.0.snsr_ User-Defined Trigger task model for backwards compatibility. + Use this to produce enrolled spotter models for DSP ports of THF 3.x. + Not recommended for general use, as recognizers created using this model have reduced performance compared to _udt-enUS-12.2.5.snsr_. - **Changed** - Improved User-Defined Trigger model, _udt-enUS-12.0.10.0.snsr_. - [getString](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) supports reading task configuration keys (such as [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type), [task-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-name), [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version).) - _custom-stream.c_ sample renamed to [alsa-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/alsa-stream.md#alsa-streamc). - [spot-enroll](https://doc.sensory.com/tnl/7.8/tools/spot-enroll.md#spot-enroll) prints a warning when the number of enrollment recordings per user is different from the recommended value, [req-enroll](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#req-enroll). - **Removed** - Removed `SNSR_RES_ENROLLED_USER`. Use [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) instead. - **Fixed** - Android sample app failed to open the audio device on Marshmallow (API level 23) and newer. - Java [open](https://doc.sensory.com/tnl/7.8/api/io.md#stream-open) and [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) methods marked as throwing `IOException`. - Small enrollment memory leak. - Removed duplicate C sample code. ## 5.0.0-beta.3 (2016-11-01) - **Added** - [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) supports live capture from a Linux ALSA source. - [C examples](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#c-examples) for Linux: + [spot-convert.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-convert.md#spot-convertc), [spot-enroll.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-enroll.md#spot-enrollc), _spot-eval.c_ sources. + [live-enroll.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-enroll.md#live-enrollc) interactive command-line enrollment. + _live-spot-sample.c_ simple one-shot spotter using live audio capture. + [live-spot-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot-stream.md#live-spot-streamc) uses a custom SnsrStream implementation from _custom-stream.c_ to do live audio capture using ALSA. - **Changed** - _spot-eval_ tool: + Supports live audio capture on Linux. + No longer shows speaker verification scores at the default verbosity level. Use `-v` to revert to previous behavior. - Allow setting [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm) to `NULL`, which can be used release a stream reference held by a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) instance. - `SnsrStreamAudioDeviceAndroid()` creates the `AudioRecord` instance in the `onOpen()` method, and releases it in `onClose()`. Previous behavior created the instance in the constructor and released it in `onRelease()`. The reduced `AudioRecord` lifespan improves audio resource contention on some Android implementations. - **Fixed** - If [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) was not set before a [wake word enrollment](https://doc.sensory.com/tnl/7.8/models/types/enroll.md#enroll-type) task started, the value set in the initial [^next](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#next) callback was ignored. - [Wake word enrollment](https://doc.sensory.com/tnl/7.8/models/types/enroll.md#enroll-type) task documentation did not reference [^resume](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#resume). - Phrase spotters with multiple enrolled phrases could return an incorrect result phrase with a [sv-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sv-score) of `1.0`. - **Security** - Using Java [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) or [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instances after calling the `release()` method now throws an exception, instead of generating a segmentation fault. ## 5.0.0-beta.2 (2016-10-09) - **Added** - Java support for macOS, Linux on x86_64, i686 and Raspberry Pi, and 64-bit Windows. - Java code samples: [enrollUDT.java](https://doc.sensory.com/tnl/7.8/api/sample/java/enrollUDT.md#enrolludtjava) and [evalUDT.java](https://doc.sensory.com/tnl/7.8/api/sample/java/evalUDT.md#evaludtjava). - Optional input audio buffering in [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) tasks. + Get segmented audio from recognition alignments. + Seamless trigger-to-search applications. - Settings: + [Wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) task: [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [audio-stream-first](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-first), [audio-stream-last](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream-last), [audio-stream-from](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-stream-from), [audio-stream-to](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-stream-to), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample). - Return codes: [BUFFER_OVERRUN](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [BUFFER_UNDERRUN](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). - [describeError](https://doc.sensory.com/tnl/7.8/api/inference.md#describeerror). - [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require) supports range operators when validating version numbers. - **Changed** - Better `snsr.h` C++ compatibility: Opaque struct handles use unique struct names. - Improved Java stack traces for exceptions thrown in user callbacks. - Documentation for constants in the `com.sensory.speech.Snsr` Java class. - **Removed** - Settings: + [Wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) task: SNSR_RES_SCORE, SNSR_RES_TOTAL_SCORE. These phrase spotting scores are highly non-linear and are not a measure of recognition confidence. ## 5.0.0-beta.1 (2016-07-12) - **Added** - Produce phrase spotter models for Sensory's deeply embedded (DSP) targets: + [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) command-line tool. + [spot-convert.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-convert.md#spot-convertc) source provided for reference. + Sample UDT and phrase spotter task models updated to support conversion to embedded formats. + Android sample app updated to show usage. - Settings: + Library: [license-exp-message](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#license-exp-message). + All tasks: [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version). + [Wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) task: [listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window), [dsp-target](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-target), [dsp-header-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-header-stream), [dsp-search-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-search-stream), [dsp-acmodel-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-acmodel-stream). + [Wake word enrollment](https://doc.sensory.com/tnl/7.8/models/types/enroll.md#enroll-type) task: [accuracy](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#accuracy). - **Changed** - [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require) behavior for the [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version) key. - Documentation: [read](https://doc.sensory.com/tnl/7.8/api/io.md#stream-read) has non-blocking behavior on [fromBuffer](https://doc.sensory.com/tnl/7.8/api/io.md#frombuffer) streams. ## 5.0.0-beta.0 (2016-06-02) - **Added** - Initial beta release of TrulyHandsfree 5.0.0. [CMake]: https://cmake.org/ "CMake: A Powerful Software Build System" [dBFS]: https://en.wikipedia.org/wiki/DBFS "Decibels relative to full scale" *[ALSA]: Advanced Linux Sound Architecture *[API]: Application Programming Interface *[SDK]: Software Development Kit *[THF]: TrulyHandsfree, Sensory's wake word and command recognition technology *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets *[VAD]: Voice Activity Detector *[WMME]: Windows Multimedia Extensions, the audio capture API on Windows --- source_path: "changes/version-6.md" canonical_url: "https://doc.sensory.com/tnl/7.8/changes/version-6/" --- # Version 6 changes **Tip:** Looking for the latest changes? See [Version 7 changes](https://doc.sensory.com/tnl/7.8/changes/index.md#v7-changes). TrulyNatural version 6 introduced support for prebuilt LVCSR models in [v6.3.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.3.0) and [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) in [v6.7.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.7.0). The API and TrulyHandsfree models are fully backwards-compatible with [version 5](https://doc.sensory.com/tnl/7.8/changes/version-5.md#v5-changes) beta. ## 6.21.2 (2023-10-25) - **Added** - Support for multi-threaded models in the _aarch64-linux-gnu_, _mipsel-buildroot-linux-uclibc_, and _mipsel-openwrt-linux-musl_ libraries. ## 6.21.1 (2023-08-29) - **Changed** - Removed calls to `Log.d()` and `Log.e()` in [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) on Android. ## 6.21.0 (2023-01-26) - **Added** - [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) `-d directory` option to write each VAD audio segment to a separate file in `directory`. - Support for multi-phrase spotters where some of the shorter vocabulary phrases are part of longer ones. For example: "control box one", "control box two", "control box three", "control box", and "control". - _(tnl)_ _tpl-opt-spot-vad-lvcsr-1.8.0.snsr_ which adds events [^listen-begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-begin), and [^listen-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-end), and settings [complete-only](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#complete-only) and [search.frame-nota](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#searchframe-nota), that were missing from _tpl-opt-spot-vad-lvcsr-1.7.0.snsr_ - **Changed** - [spot-eval-batch](https://doc.sensory.com/tnl/7.8/tools/snsr-eval-batch.md#snsr-eval-batch) shows a warning if any in-vocabulary test file does not contain sufficient lead-in audio before the target phrase. - Documentation for [spot-eval-batch](https://doc.sensory.com/tnl/7.8/tools/snsr-eval-batch.md#snsr-eval-batch): + Notes lead-in audio requirements for in-vocabulary test files. + Expands the description of `INVFA` log file entries. - DSP library (for creating embedded spotter models) version 7.1.0. - Improved model inference speed on Arm Cortex-M4. - _(tnl)_ Lower RAM requirement for recognizers on small embedded platforms. - _(tnl)_ Removed the `` recognition result. Recognizers that previously returned this now return `` instead. See [grammar special symbols](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-special) for details on ``. - **Removed** - _(tnl)_ _tpl-opt-spot-vad-lvcsr-1.7.0.snsr_ - **Fixed** - Reduced the (low) likelihood of exceeding [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit). - _tpl-spot-vad-3.7.0.snsr_ could raise a spurious [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin) directly after [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end). - _(tnl)_ With [complete-only](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#complete-only) `== 1,` [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) could occasionally be an empty string instead of ``. - _(tnl)_ _tpl-vad-lvcsr-3.7.0.snsr_ could report a buffer error if [auto-flush](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#auto-flush) was set before [trailing-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#trailing-silence). ## 6.20.1 (2022-11-14) - **Added** - [push-audio.c](https://doc.sensory.com/tnl/7.8/api/sample/c/push-audio.md#push-audioc) project files for Microsoft Visual Studio. - **Changed** - [push-audio.c](https://doc.sensory.com/tnl/7.8/api/sample/c/push-audio.md#push-audioc) uses live audio if the now optional audio filename isn't provided. - **Fixed** - With [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit) `> 0`, [push-buffer-backlog](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-buffer-backlog) increased monotonically, eventually leading to a [NOT_ENOUGH_SPACE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) error. - VAD [templates](https://doc.sensory.com/tnl/7.8/models/index.md#templates) in 6.20.0 allocated a ring buffer that was too small for cases where speech was found just before the [trailing-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#trailing-silence) timeout. This could result in a runtime [ARG_OUT_OF_RANGE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) error. ## 6.20.0 (2022-11-02) - **Added** - [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) and [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop) to better support use cases where the application controls audio capture ("push mode") rather than the TrulyNatural SDK ("pull mode"). + These functions **do** support models with internal threading. - Support for limiting the amount of time spent in any one call to [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push). See [push-duration-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-duration-limit), [push-buffer-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-buffer-size), [push-buffer-backlog](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#push-buffer-backlog). - [CLOCK_FUNC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_clock_func) to support push duration limits. - _spot-voicegenie-enUS-6.5.0-m.snsr_ fixed-phrase spotter for "Voice Genie" with improved performance over the previous version. - Updated VAD [templates](https://doc.sensory.com/tnl/7.8/models/index.md#templates) with lower RAM requirements: + _tpl-spot-vad-3.7.0.snsr_ + _(tnl)_ _tpl-opt-spot-vad-lvcsr-1.7.0.snsr_ + _(tnl)_ _tpl-spot-vad-lvcsr-3.7.0.snsr_ + _(tnl)_ _tpl-vad-lvcsr-3.7.0.snsr_ - _(tnl)_ Documentation section that shows how to [use class libraries from code](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-class-libraries-api). - _(tnl)_ [grammar-syntax](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-syntax) notes that the effects of `:` terminal rewrites are used in [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot), but not in [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result). - _(tnl)_ LVCSR models with improved pronunciation modeling: + _(tnl)_ _lvcsr-background-enUS-1.1.0.snsr_ + _(tnl)_ _lvcsr-broad-enUS-3.1.0-t5.snsr_ + _(tnl)_ _lvcsr-build-enUS-2.6.0.snsr_ - _(tnl)_ [lvcsr-lib-enUS-1.2.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#lvcsr-lib-enUS) with updated classes. Note that many class names have changed for improved compatibility with [VoiceHub](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub). - **Changed** - [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) `-l` flag to reduce output verbosity. - _snsr.h_ no longer includes `.` - _push-spot.c_ sample renamed to [push-audio.c](https://doc.sensory.com/tnl/7.8/api/sample/c/push-audio.md#push-audioc) + Uses new [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) APIs. + Supports [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot), [phrasespot-vad](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot-vad), [lvcsr](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#lvcsr), and [vad](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#vad) task types. - [spot-data.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data.md#spot-datac) uses new [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) APIs. - DSP library (for creating embedded spotter models) version 7.0.0. - _(tnl)_ [complete-only](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#complete-only) defaults to on, `1`. Revert to previous behavior by setting `complete-only = 0`. - _(tnl)_ If [complete-only](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#complete-only) filters out an incomplete recognition result, [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) will be `` instead of an empty string. - _(tnl)_ Lower RAM requirement for recognizers on small embedded platforms. - **Deprecated** - [auto-flush](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#auto-flush) - **Removed** - _spot-voicegenie-enUS-6.4.0-m.snsr_ - _tpl-spot-vad-3.4.0.snsr_ - _(tnl)_ _lvcsr-background-enUS-1.0.1.snsr_ - _(tnl)_ _lvcsr-broad-enUS-3.0.0-t5.snsr_ - _(tnl)_ _lvcsr-build-enUS-2.5.1.snsr_ - _(tnl)_ _lvcsr-lib-enUS-1.1.0.snsr_ - _(tnl)_ _tpl-opt-spot-vad-lvcsr-1.4.0.snsr_ - _(tnl)_ _tpl-spot-vad-lvcsr-3.5.0.snsr_ - _(tnl)_ _tpl-vad-lvcsr-3.5.0.snsr_ - **Fixed** - _(tnl)_ LVCSR recognizer could produce a spurious [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) when used with the lightweight VAD and recognizing from file. - _(tnl)_ Missing [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) when using [tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-vad-lvcsr.md#tpl-vad-lvcsr-type) with [include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence) `= 1`. - _(tnl)_ Missing [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) when using a VAD template and recognizing from an audio file without sufficient trailing silence. - _(tnl)_ Unexpected recognition or NLU result after replacing a recognition class at runtime. - **Security** - [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) `-q setting-name` could cause a segmentation fault if the value for `setting-name` was `NULL.` - Retrieving the [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator) for a continuously adapting model in a template slot, by explicitly specifying the slot, in an older template that does not support [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator), could cause an invalid memory reference. - [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) could fail with a `NULL` pointer dereference when attempting to load from a truncated model file or stream. - The [allocTLSF](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloctlsf) allocator could fail with an out-of-bounds memory read when the provided pool blocks were exhausted. ## 6.19.0 (2022-05-20) - **Added** - Library for _armv6-linux-gnueabihf_, for use on the Raspberry Pi Zero. - [^adapt-started](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapt-started) for continuously adapting spotter models. - [ca-voicegenie-enUS-1.1.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#ca-voicegenie-enUS) US English spotter for "voice genie" that continuously adapts to one or more users. Includes support for [^adapt-started](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapt-started). - Support for saving continuous adaptation spotter enrollment contexts from [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), and loading these with [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load). - TrulyNatural is available as an XCFramework for iOS as _lib/ios/snsr.xcframework_. - [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) reports [^adapt-started](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapt-started), [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), and [^new-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#new-user) when run with increased verbosity (one or more `-v` flags). - [live-enroll](https://doc.sensory.com/tnl/7.8/tools/live-enroll.md#live-enroll) `-p` option saves enrollment recordings to file. - Updated [templates](https://doc.sensory.com/tnl/7.8/models/index.md#templates) with support for [^adapt-started](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapt-started), [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), [delete-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#delete-user), [^new-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#new-user), [rename-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#rename-user), [user-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#user-count), [user-index](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#user-index), [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user), and [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator): + _tpl-spot-concurrent-1.4.0.snsr_ + _tpl-spot-debug-1.4.0.snsr_ + _tpl-spot-dynop-1.4.0.snsr_ + _tpl-spot-select-1.4.0.snsr_ + _tpl-spot-sequential-1.4.0.snsr_ + _tpl-spot-vad-2.4.0.snsr_ + _tpl-spot-vad-3.4.0.snsr_ + _(tnl)_ _tpl-opt-spot-vad-lvcsr-1.4.0.snsr_ + _(tnl)_ _tpl-spot-lvcsr-1.4.0.snsr_ - _(tnl)_ [complete-only](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#complete-only) setting. - _(tnl)_ LVCSR models with support for [complete-only](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#complete-only) setting: + _lvcsr-background-enUS-1.0.1.snsr_ includes a small language model to match out-of-grammar utterances. + _lvcsr-broad-enUS-3.0.0-t5.snsr_ is a large multi-threaded speech-to-text recognizer for US English. + _lvcsr-build-enUS-2.5.1.snsr_ with improved pronunciation modeling. - **Changed** - [live-enroll](https://doc.sensory.com/tnl/7.8/tools/live-enroll.md#live-enroll), [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit), [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval), and [spot-enroll](https://doc.sensory.com/tnl/7.8/tools/spot-enroll.md#spot-enroll) report model and library expiration dates when invoked with two or more `-v` flags. - _arm-none-eabihf_ optimized for size `-Os,` instead of speed, `-O3`. - Reduced [cache-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#cache-file) size by 6 MiB. - Code emitted by [SUBSET_INIT](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_subset_init) and [SOURCE](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source) has improved compatibility with C++ compilers. - iOS PhraseSpot sample app uses _snsr.xcframework_ - _(tnl)_ Documentation for [search.frame-nota](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#searchframe-nota) notes that this value should not be modified for recognizers that include statistical language model components. - **Removed** - _tpl-opt-spot-vad-lvcsr-1.0.3.snsr_ - _tpl-spot-concurrent-1.2.0.snsr_ - _tpl-spot-debug-1.3.0.snsr_ - _tpl-spot-dynop-1.2.0.snsr_ - _tpl-spot-select-1.2.0.snsr_ - _tpl-spot-sequential-1.3.0.snsr_ - _tpl-spot-vad-2.1.0.snsr_ - _tpl-spot-vad-3.1.0.snsr_ - _(tnl)_ _lvcsr-background-enUS-1.0.0.snsr_ - _(tnl)_ _lvcsr-broad-enUS-3.0.0-t5.snsr_ - _(tnl)_ _lvcsr-build-enUS-2.5.0.snsr_ - _(tnl)_ _tpl-spot-lvcsr-1.3.0.snsr_ - **Fixed** - Spurious [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end) when running a VAD over a very short file. During this mistaken callback [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms) was not available. - Enrolling continuously adapting spotters logged progress to `stdout.` - Loading a Continuous Adaptation spotter context with [cache-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#cache-file) and renaming an enrolled user before running the session for the first time resulted in de-referencing of a `NULL` pointer. - Continuous Adaptation spotter [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator) did not show any enrolled users loaded from [cache-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#cache-file) until the session was run. - Continuous Adaptation spotter [cache-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#cache-file) overwrote the previous version of the file. If the application was interrupted while writing, this context file could be corrupted. Enrollment contexts are now saved to a temporary file in the same directory, then `rename()d` to the desired cache file in an atomic operation. - Continuous Adaptation spotter [cache-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#cache-file) blocked the main thread while writing the enrollment context. On slow file systems this could lead to a recording buffer overflow. Now writes this context in a background thread. - Continuous Adaptation spotter [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted) would be delayed until the next detection if the spotter was used in slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1) of [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-sequential.md#tpl-spot-sequential-type). - _(tnl)_ Decreasing [result-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#result-max) took effect only after saving and then reloading a model. - **Security** - Calling [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) `-i` with two or more `-t` arguments to create custom initialization code could result in a use-after-free memory error. ## 6.18.1 (2022-02-22) - **Added** - _(tnl)_ _tpl-opt-spot-vad-lvcsr-1.0.3.snsr_ with support for VAD events: [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin), [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end), [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit), and [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence). - **Removed** - _tpl-opt-spot-vad-lvcsr-1.0.2.snsr_ - **Fixed** - Clarify that [user-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#user-count) is only available with [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) models that continuously adapt. - Incorrect sample snippet in the documentation for [allocPerf](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocperf). - _(tnl)_ `` recognition result returned instead of `` for recognizers that can never return a valid result. - _(tnl)_ Models configured to use a limited amount of RAM could gradually become less accurate over time. - _(tnl)_ Example code for _lvcsr-background-enUS_. - _(tnl)_ The memory use of recognizers configured to use N-best (`result-max > 1`) increased over time. - **Security** - _(tnl)_ An older, task-specific custom recognizer configured to use N-best recognition results caused an invalid memory access in release 6.18.0. ## 6.18.0 (2022-02-15) - **Added** - Support for enrolled fixed trigger models with audio segmentation done with a phrase spotter instead of a VAD. These models support [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator) to find the enrolled fixed phrase text. - Support for fixed trigger models that continuously adapt to one or more users. These models support optional settings: [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted), [cache-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#cache-file), [delete-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#delete-user), [max-users](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-users), [^new-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#new-user), [rename-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#rename-user), [user-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#user-count), [user-index](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#user-index), [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user), and [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator). - _ca-voicegenie-enUS-1.0.0.snsr_ US English spotter for "voice genie" that continuously adapts to one or more users. - iOS PhraseSpot sample app supports Bluetooth headsets. - Library for _arm-none-eabihf_. - `lib//README-.md` with port-specific build details. These files list the toolchain name, version, flags, and macros used to build the library for _platform_. - Determine whether multi-threading is supported: [THREAD_SUPPORT](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_thread_support). - Support for replacing the fatal error function, [PANIC_FUNC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_panic_func). - Support for replacing the dynamic memory allocator used by the TrulyNatural SDK. This is useful on small embedded platforms where dynamic memory allocation is either not available, or not best practice. See [Provider](https://doc.sensory.com/tnl/7.8/api/io.md#provider), [AllocRC](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocrc), [ALLOC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc), [ALLOC_ADD_POOL](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc_add_pool). - New memory allocator implementations: [allocStdlib](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocstdlib), [allocBuddy](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocbuddy), [allocTLSF](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloctlsf), [allocLock](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloclock). - Optional memory allocator instrumentation wrapper: [allocPerf](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocperf), [allocPerfStats](https://doc.sensory.com/tnl/7.8/api/library-config.md#allocperfstats). - New heap allocator functions that use the TrulyNatural dynamic memory manager: [malloc](https://doc.sensory.com/tnl/7.8/api/heap.md#malloc), [free](https://doc.sensory.com/tnl/7.8/api/heap.md#free), [realloc](https://doc.sensory.com/tnl/7.8/api/heap.md#realloc). - New FAQ section: [Can I avoid dynamic memory allocation?](https://doc.sensory.com/tnl/7.8/faq.md#custom-heap-allocator) - [fromAudioFile](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiofile). - [ALLOCATOR_EXISTS](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [NOT_SUPPORTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_not_supported). - Updated [Enrolled wake word](https://doc.sensory.com/tnl/7.8/models/index.md#enroll-models) models. These use a machine-learned VAD for improved audio segmentation: + [eft-hbg-enUS-23.0.0.9.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#eft-hbg-enUS) "Hello Blue Genie" US English fixed wake word. + [udt-universal-3.66.1.9.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#udt-universal) New User-Defined Trigger enrollment model suitable for use with most languages. + [udt-enUS-5.1.1.9.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#udt-enUS) User-Defined Trigger enrollment with models compatible with TrulyHandsfree 3.x DSP ports. - _tpl-spot-sequential-1.3.0.snsr_ allows optional looping on [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1). This is controlled with [loop](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#loop), which defaults to `0` for the old behavior. - _(tnl)_ Description of **broad** and **background** recognition models in [LVCSR](https://doc.sensory.com/tnl/7.8/models/index.md#lvcsr-models). - _(tnl)_ LVCSR models: + _lvcsr-background-enUS-1.0.0.snsr_ includes a small language model to match out-of-grammar utterances. + _lvcsr-broad-enUS-3.0.0-t5.snsr_ is a large multi-threaded speech-to-text recognizer for US English. + _lvcsr-build-enUS-2.5.0.snsr_ with improved pronunciation modeling. - _(tnl)_ _tpl-opt-spot-vad-lvcsr-1.0.2.snsr_ runs a large vocabulary recognizer gated by either a spotted phrase, or just a VAD, selectable at runtime. - **Changed** - [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) includes a `-q` option to query setting values. - [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) writes to _edited-model.snsr_ only if the model was updated with `-f,` `-g,` or `-s.` - [spot-enroll](https://doc.sensory.com/tnl/7.8/tools/spot-enroll.md#spot-enroll) and [live-enroll](https://doc.sensory.com/tnl/7.8/tools/live-enroll.md#live-enroll) show enrollment vocabulary, if the model supports it. - [spot-eval-batch](https://doc.sensory.com/tnl/7.8/tools/snsr-eval-batch.md#snsr-eval-batch) log file format includes [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score). - [library-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-info) includes whether multi-threading is supported. - Improved precision on intermediate values during model inference. This can result in small changes in alignments and scores with the same model, compared to earlier releases. - Increased the audio amplitude of _data/audio/enrollments/terminator-2*.wav_ sample files to pass the audio quality checks when enrolling with [udt-universal-3.66.1.9.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#udt-universal) - Reworded error message for [EOF](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_eof). - DSP library (for creating embedded spotter models) version 6.7.2. - The [spot-data.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data.md#spot-datac) sample uses the [allocTLSF](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloctlsf) allocator to avoid dynamic memory allocation, and [PANIC_FUNC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_panic_func) to recover from out-of-memory conditions. - Java build and publishing scripts upgraded to Gradle version 7.4. This adds compatibility for Java versions 8 through 17. - Java sample code uses `com.github.gmazzo.buildconfig` instead of `de.fuerstenau.buildconfig` for compatibility with Gradle 7. - [fromAudioFile](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiofile) writes directly to file and updates the audio file header after each write. - Android sample applications use Gradle 7 and `compileSdkVersion 31`, which require Android Studio Bumblebee and Java 11. - Preprocessor macros generated by [dsp-header-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-header-stream) and [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) include only ASCII characters. This improves compatibility with old toolchains. Example: ```c /* Old format */ #define G_grammarLabel_ハイゲーム (1) /* New format */ #define PHRASE_1 "\xE3\x83\x8F\xE3\x82\xA4\xE3\x82\xB2\xE3\x83\xBC\xE3\x83\xA0" /* ハイゲーム */ ``` - _(tnl)_ New `` recognition result to distinguish transient out-of-memory conditions from poor recognition confidence. See [grammar special symbols](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-special). - **Removed** - [Enrolled wake word](https://doc.sensory.com/tnl/7.8/models/index.md#enroll-models) models + _eft-hbg-enUS-23.0.0.8-tssv.snsr_ + _eft-hbg-enUS-23.0.8.0.snsr_ + _udt-enUS-2.66.3.0.snsr_ + _udt-enUS-5.1.1.7.snsr_ + _udt-enUS-5.1.1.7-tssv.snsr_ + _udt-enUS-12.0.10.7.snsr_ + _tpl-spot-sequential-1.2.0.snsr_ - [LVCSR](https://doc.sensory.com/tnl/7.8/models/index.md#lvcsr-models) models + _lvcsr-broad-enUS-2.3.0.snsr_ + _lvcsr-build-enUS-2.3.0.snsr_ - **Fixed** - If [spot-enroll](https://doc.sensory.com/tnl/7.8/tools/spot-enroll.md#spot-enroll) rejected an enrollment audio file it over-reported the number of failed enrollments. - Re-loading a model into a template slot after a callback handler was registered could fail. - Intermediate result overflows during model inference. These overflows were limited to large models, and could result in less than optimal performance under certain acoustic conditions. - Spotter enrollment could fail with `Audio chunk input buffer overflow: limit is 10.000 seconds` - [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require) with [task-type-and-version-list](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type-and-version-list) allows spaces around the `;` tuple separator. - _sample/c/CMakeLists.txt_ failed to link samples on macOS due to a missing `Accelerate` framework dependency. - _(tnl)_ [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) models built with TrulyNatural 6.16.0 or earlier did not invoke the [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) callback in TrulyNatural 6.17.0. - _(tnl)_ The TrulyNatural SDK allocated more heap than needed for LVCSR models. The amount of additional RAM needed was almost always negligible, but would increase each time a model was re-saved. - _(tnl)_ Poor example use of `~s.timer-phrases` in [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition). The `~s.timer-phrases` class already includes typical requests phrases such as "set a timer for", the example duplicated this. - _(tnl)_ Models configured to use a limited amount of RAM reported `` if this limit was reached. Now reports the result best matching the input audio instead. - _(tnl)_ A [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) example still showed the pre-6.16.0 recognition result that included terminals replaced with `:`. Replacements are now only available in NLU results. - **Security** - If a callback handler function: Returned one of a small set of [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) error codes, and it set a message with [describeError](https://doc.sensory.com/tnl/7.8/api/inference.md#describeerror), and this error message was shorter than 20 bytes, then an out-of-bounds memory write could occur. - [reset](https://doc.sensory.com/tnl/7.8/api/inference.md#reset) could cause a segmentation fault if it was called before [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run). ## 6.17.0 (2021-07-29) - **Added** - _(tnl)_ Support for N-best phrase-level recognition results. New settings: + [result-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#result-max), [result-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#result-count), [result-index](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#result-index). - **Changed** - _(tnl)_ [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) reports N-best recognition results, when enabled. - _(tnl)_ Updated [models](https://doc.sensory.com/tnl/7.8/models/index.md#models) with support for N-best recognition settings: + _lvcsr-broad-enUS-2.3.0.snsr_ + _lvcsr-build-enUS-2.3.0.snsr_ + _tpl-spot-lvcsr-1.3.0.snsr_ + _tpl-spot-vad-lvcsr-2.4.0.snsr_ + _tpl-spot-vad-lvcsr-3.5.0.snsr_ + _tpl-vad-lvcsr-2.5.0.snsr_ + _tpl-vad-lvcsr-3.5.0.snsr_ - _(tnl)_ [grammar special symbols](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-special) notes that `` should not be used in NLU grammars. - _(tnl)_ Known issues. - **Fixed** - Model publishing to Maven repositories failed with recent JVM versions. - 64-bit Windows libraries did not use MMX acceleration. - [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) crashed instead of displaying an error message for unsupported DSP targets. - [spot-enroll](https://doc.sensory.com/tnl/7.8/tools/spot-enroll.md#spot-enroll) did not report files that were skipped due to speech detection failure as enrollment errors. - _(tnl)_ [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) 6.16.0 reported error `Setting "nlu-match-count" not found.` when used with older recognition models. ## 6.16.0 (2021-06-06) - **Added** - [LICENSE_LIMIT_EXCEEDED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). - `-g` command-line option in [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) and [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit). - Support for Apple Silicon in _lib/macos/libsnsr.a_ on macOS. - _(tnl)_ [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) grammar support for class output replacement. For example: `~classname:` suppresses all recognition output from the class. - _(tnl)_ Lightweight NLU processor: + Now a separate step after recognition is complete. See [nlu-grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#nlu-grammar-stream) and [LVCSR with lightweight NLU parsing](https://doc.sensory.com/tnl/7.8/faq.md#lvcsr-nlu) + Can be used with broad domain recognition models. + Supports a wildcard symbol `.` that matches any word. + Optionally reports multiple matches in case of ambiguity. See [nlu-match-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-match-count), [nlu-match-index](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-match-index), and [nlu-match-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-match-max). + [nlu-word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-word-iterator) iterates over the parsed NLU result words. - **Changed** - [enrollment-id](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#enrollment-id) available in [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail). - [model-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#model-name) is used when creating embedded models. - [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) includes information regarding provenance and licensing in the C output files it creates. - _tpl-spot-concurrent-1.2.0.snsr_ no longer sets the [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) for spotters in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0) and slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1). Previous behavior forced these to have the same sensitivity, which limited utility. - [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-sequential) notes that [^listen-begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-begin) and [^listen-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-end) mark the begin and end of audio focus shifting to slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1). - Reference documentation updated for [include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence). - [spot-eval-batch](https://doc.sensory.com/tnl/7.8/tools/snsr-eval-batch.md#snsr-eval-batch) enforces an in-vocabulary lead-in audio requirement for low false-accept spotter models. It still skips in-vocabulary test files that are too short, but the minimum required duration for new models is now one second. If needed, update old models with: ```sh snsr-edit -v -t old-model.snsr -o new-model.snsr -s min-in-vocab-duration=1000 ``` - DSP library (for creating embedded spotter models) version 6.6.0. - macOS libraries target 11.0. - [fromFileName](https://doc.sensory.com/tnl/7.8/api/io.md#fromfilename) supports opening files in text mode. - _(tnl)_ _tpl-spot-select-1.2.0.snsr_ supports NLU results. - _(tnl)_ Reference documentation updated for [tpl-spot-vad](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad) and [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr). - _(tnl)_ [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) reports multiple NLU matches when [nlu-match-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-match-max) and [nlu-match-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-match-count) are larger than `1`. - _(tnl)_ A reference to a library class (those named `~s.*`) not found in the loaded [class library](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-class-libraries) is reported as an error. - _(tnl)_ The broad-domain model, `lvcsr-broad-enUS-2.2.0.snsr,` includes a class slot for optional leading vocabulary. - _(tnl)_ Updated [models](https://doc.sensory.com/tnl/7.8/models/index.md#models), with support for new NLU features: + _lvcsr-broad-enUS-2.2.0.snsr_ + _lvcsr-build-enUS-2.2.0.snsr_ + _lvcsr-lib-enUS-1.1.0.snsr_ + _tpl-spot-lvcsr-1.2.0.snsr_ + _tpl-spot-select-1.2.0.snsr_ - _(tnl)_ Updated [models](https://doc.sensory.com/tnl/7.8/models/index.md#models), with support for new NLU features, [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream), and [phrases-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#phrases-stream): + _tpl-spot-vad-lvcsr-2.3.0.snsr_ + _tpl-spot-vad-lvcsr-3.4.0.snsr_ + _tpl-vad-lvcsr-2.4.0.snsr_ + _tpl-vad-lvcsr-3.4.0.snsr_ - **Deprecated** - [delay](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#delay). - _(tnl)_ Support for [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) tags specified with `\@`. - **Fixed** - If [spot-enroll](https://doc.sensory.com/tnl/7.8/tools/spot-enroll.md#spot-enroll) detected a problem with an enrollment recording, the error message could refer to the wrong filename. - When used with one of the [VAD models](https://doc.sensory.com/tnl/7.8/models/index.md#vad-models), [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) reported a `Stopped by callback` error when invoked with minimal verbosity. - Loading a different model into a filled template slot could lead to an unexpected failure. - _(tnl)_ LVCSR recognizer leaked memory when the lightweight VAD was used and [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval) was set to `0` - _(tnl)_ _lvcsr-lib-enUS-1.0.0.json_ was a duplicate of _lvcsr-lib-enUS-1.0.0.snsr_ instead of a text file with JSON data. - **Security** - Low false-accept spotter models with pronunciations that contained certain language-specific phonemes could cause out-of-bounds writes to the heap. - When creating C output (`-c` command-line option), [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) could mistakenly use memory that had been freed. This was a coding error in the sample code for the utility, not an issue in the TrulyNatural library. - _(tnl)_ Invalid weight markup in [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) grammars could lead to a buffer overflow during parsing. ## 6.15.0 (2021-01-21) - **Added** - Compatibility with models created by [VoiceHub](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub). - [dsp.t-slice-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#dspt-slice-version), [dsp.production-ready](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#dspproduction-ready). - [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score). - _(tnl)_ _lvcsr-lib-enUS-1.0.0.snsr_, a binary class-library that contains common grammar snippets. Use this with _lvcsr-broad-enUS-2.1.0.snsr_ and _lvcsr-build-enUS-2.1.0.snsr_ to simplify [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) grammars. See [class libraries](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-class-libraries) and the [LVCSR](https://doc.sensory.com/tnl/7.8/models/index.md#lvcsr-models) section in [models](https://doc.sensory.com/tnl/7.8/models/index.md#models). - **Changed** - [getStream](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) supports reading models from slots in [task templates](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type). - [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) output filenames include [dsp.t-slice-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#dspt-slice-version), and `prod` for production-ready models or `dev` for development-only ones. For example: _spot-hbg-enUS-1.3.0-m-pc38-3.4.0-op10-prod-net.c_ for [dsp.t-slice-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#dspt-slice-version) `== "3.4.0"` and [dsp.production-ready](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#dspproduction-ready) `== 1`. - When converting model files that expire, or have duration or recognition limits enabled, to embedded (DSP) format, [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) creates acoustic model files that are also limited. These limited models require a recent Sensory embedded spotter library (6.4.0 or later) to run. - [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) has a new `-q slotname` argument to support conversion of spotter models in template slots such as [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-sequential). - [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) option `-o` to exclude [dsp.t-slice-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#dspt-slice-version), the operating point, and production-readiness from generated output filenames. - DSP library (for creating embedded spotter models) version 6.4.0. - _tpl-spot-sequential-1.2.0.snsr_ includes the last 300 ms of audio before the end of the recognition in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0) in the audio sent to slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1). This improves slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1) recognition performance in cases where there's no pause between the phrase spotted by slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0) and that spotted by slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1). - [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) option `-e` extracts the contents of a template slot into a file. - Applications linked with custom initialization code no longer support file format conversion to embedded (DSP) targets. This reduces code size by removing a little-used feature. + See [model:ids](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#modelids), [SUBSET_INIT](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_subset_init), and [FAQ entry](https://doc.sensory.com/tnl/7.8/faq.md#reduce-code-size). + These settings are not available when compiling with `-DSNSR_USE_SUBSET`: [dsp-target](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-target), [dsp-header-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-header-stream), [dsp-search-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-search-stream), and [dsp-acmodel-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-acmodel-stream). - Sample applications initialize [SECURITY_CHIP](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_security_chip) when `SNSR_USE_SECURITY_CHIP` is defined. - TrulyNatural SDK now requires Android [API level 16][api-levels] or later. - Models and templates updated to support new settings: _spot-hbg-enUS-1.4.0.snsr_, _spot-music-enUS-1.2.0.snsr_, _spot-voicegenie-enUS-6.4.0.snsr_, _tpl-spot-vad-3.1.0.snsr_, _tpl-spot-concurrent-1.1.0.snsr_, _tpl-spot-debug-1.3.0.snsr_, _tpl-spot-dynop-1.2.0.snsr_, _tpl-spot-select-1.1.0.snsr_, _tpl-spot-sequential-1.2.0.snsr_, _tpl-spot-vad-2.1.0.snsr_. - _(tnl)_ Relaxed the ordering requirement for [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) rules. Variables no longer need to be defined before they are referenced, as long as they are defined somewhere in the grammar. Recursive rule definitions are flagged as errors. - _(tnl)_ [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) supports nested recognition classes. - _(tnl)_ Models and templates updated to support class libraries and new settings: _lvcsr-broad-enUS-2.1.0.snsr,_ _lvcsr-build-enUS-2.1.0.snsr_, _tpl-spot-vad-lvcsr-3.3.0.snsr_, _tpl-vad-lvcsr-3.3.0.snsr_, _tpl-spot-lvcsr-1.1.0.snsr_, _tpl-vad-lvcsr-2.3.0.snsr_. - **Fixed** - NEON acceleration not enabled on iOS. - Sample iOS PhraseSpot app does not support Dark Mode. - Reading [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) from [task templates](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) would fail unless it had been explicitly set. This now returns the value from the spotter in the appropriate slot instead. - _(tnl)_ Recognition results were set to `` for all [search.frame-nota](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#searchframe-nota) values larger than `0`. This regression first occurred in 6.14.0. - _(tnl)_ Attempts to get values for [nlu-slot-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-name), [nlu-slot-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-value), or [nlu-slot-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-count) succeeded and returned `NULL` or `0` even when these values were not available. Now returns [SETTING_NOT_AVAILABLE](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). - _(tnl)_ _tpl-spot-vad-lvcsr-2.2.0.snsr_ and _tpl-spot-vad-lvcsr-3.2.0.snsr_ could mistakenly return [ELEMENT_API_VIOLATION](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). - _(tnl)_ The `number` rule in the example NLU slot grammar (_data/grammars/enrollments-nlu-slot.txt_) listed `653` instead of `643`. `643` is used in the example utterances. - **Security** - _(tnl)_ Setting [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream) or [phrases-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#phrases-stream) more than once for the same model could access freed heap memory. ## 6.14.0 (2020-05-04) - **Added** - Model license key expiration settings: [model-license-exp-date](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#model-license-exp-date), [model-license-exp-message](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#model-license-exp-message), and [model-license-exp-warn](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#model-license-exp-warn). - Support for custom [little-big spotter models](https://doc.sensory.com/tnl/7.8/faq.md#little-big) with lower latency and improved false reject / false accept performance. - _(tnl)_ Improved efficiency (lower average CPU use) for all LVCSR recognizers. - _(tnl)_ Experimental support for LVCSR models with lower size requirements for a given word error rate. - **Changed** - _udt-enUS-2.66.3.0.snsr_ more reliably rejects inconsistent enrollment phrases. Creates enrolled spotter models with a wider selection of operating points. - [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) and [spot-eval-batch](https://doc.sensory.com/tnl/7.8/tools/snsr-eval-batch.md#snsr-eval-batch) do not report the now deprecated [confidence-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#confidence-score). - DSP library (for creating embedded spotter models) version 6.3.0. - [listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window) values larger than `120` are in ms. - [models](https://doc.sensory.com/tnl/7.8/models/index.md#models) in this distribution are licensed with a non-expiring license key. - **Deprecated** - The settings [confidence-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#confidence-score) and [task-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-name) are deprecated and will be removed from a future major release of the TrulyNatural SDK. Do not use these in new code. - **Removed** - _spot-voicegenie-enUS-1.1.0-m.snsr,_ due to the deprecation of [confidence-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#confidence-score). Use spot-voicegenie-enUS-6.3.0-m.snsr instead. - **Fixed** - Installer application failed if the `HOME` environment variable pointed to an invalid or read-only directory. ## 6.13.1 (2020-02-20) - **Added** - _(tnl)_ Operator precedence table in [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) documentation. - _(tnl)_ Example NLU slot grammar, _data/grammars/enrollments-nlu-slot.txt_. - _(tnl)_ FAQ entry: [LVCSR with lightweight NLU parsing](https://doc.sensory.com/tnl/7.8/faq.md#lvcsr-nlu). - **Fixed** - _(tnl)_ [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream) and [phrases-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#phrases-stream) definitions were missing a trailing `.` Note that this fix introduces a potential incompatibility with release 6.13.0. If you were using [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream) `".classname"` please revert to the syntax used in the documentation: [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream) `"classname"` - _(tnl)_ If the first symbol on a grammar path included slot markup, [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) was occasionally invoked for empty text results. - **Security** - _(tnl)_ [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) could cause a segmentation fault for unsupported input in languages that require orthographic normalization (Mandarin, Japanese, etc.). Support for these languages was introduced in 6.13.0. ## 6.13.0 (2020-02-11) - **Added** - Full-text documentation search. - _(tnl)_ [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) supports slot-capturing semantic markup with the`{ }` operator. + [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) callback for with slot results. + [nlu-slot-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-name), [nlu-slot-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-value), [nlu-slot-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-count), and [nlu-slot-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#nlu-slot-iterator) to iterate over available slot result names. - _(tnl)_ [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) supports recognition classes. - _(tnl)_ [LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type) tasks include support for an experimental lightweight VAD. - New settings: [backoff](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backoff), [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin), [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end), [hold-over](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#hold-over), [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence), [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit), [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording), [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample), [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence), and [trailing-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#trailing-silence). - Spotter-to-LVCSR template that uses the experimental lightweight VAD: _tpl-spot-lvcsr-1.0.0.snsr._ - **Changed** - Known issues. - DSP library (for creating embedded spotter models) version 6.2.2. - Reduced the set of enrollment failure reasons that require starting over with all new enrollments. [reason](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason) values of `spot,` `rec-variance,` `poor-rec-limit,` and `repetition` now require just the failed enrollment to be replaced. - _udt-enUS-2.66.1.1.snsr,_ creates smaller enrolled spotter models than the previous _udt-enUS-2.88.9.7.snsr,_ with similar performance. - [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval): - Supports [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type) task types. - Reads audio from `stdin` if the audio filename is `-.` - _(tnl)_ Broad-domain speech-to-text with improved accuracy and support for a user-defined custom recognition slot: _lvcsr-broad-enUS-2.0.0.snsr_. - _(tnl)_ US English model with [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) support: _lvcsr-build-enUS-2.0.0.snsr_. - _(tnl)_ VAD / LVCSR template models include support for slot-capturing semantic markup: _tpl-spot-vad-lvcsr-2.2.0.snsr_, _tpl-spot-vad-lvcsr-3.2.0.snsr_, _tpl-vad-lvcsr-2.2.0.snsr_, and _tpl-vad-lvcsr-3.2.0.snsr_. - **Fixed** - _(tnl)_ The [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream) parser supports weights on variables (non-terminal symbols), and provides improved error reporting. - _(tnl)_ Removed the `-ln(p)` weight formula from [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) documentation. Always use `-log10(p)` for symbol weights. - _(tnl)_ Silence markers (``, ``, and ``) were sometimes included in the recognition result, even when [show-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#show-silence) was set to `0`. - _(tnl)_ [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition): - `rule = a b c; g = $rule:symbol;` produced `symbol a b c` instead of `symbol`. - `g` crashed instead of reporting an error. - `g = ;` was not flagged as an error. - `g = a $g;` crashed instead of reporting an error. - `a*` was equivalent to `a+` instead of `[a+]`. - `@/1@` was parsed as input symbol `@` with weight `1`, instead of semantic tag `@/1@`. - Mismatched parentheses and brackets such as `g = ( a [ )` was not flagged as an error. - The grammar parser leaked memory when reporting some error types. - The pronunciation prediction engine generated too many alternates for particularly long "words", such as [UUIDs][UUID]. This incurred a large heap overhead and slowed down custom grammar builds. - **Security** - Corrected possible double `free()` during enrollment when the [^progress](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#progress) handler return a code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok). ## 6.12.0 (2019-10-17) - **Changed** - Reduced CPU load on ARM with NEON. - New [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) command-line options: + `-a`: convert all the operating points in a snsr model to embedded format. + `-c`: produce C output files in addition to the standard _.bin_ format. - [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) output filenames include the operating point, for example: _spot-hbg-enUS-1.3.0-m-pc38-op10-net.c_ for [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) `10`. - [spot-eval-batch](https://doc.sensory.com/tnl/7.8/tools/snsr-eval-batch.md#snsr-eval-batch) writes [confidence-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#confidence-score) or [sv-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sv-score) to the log file for `INVFA`, `INVTA`, and `OOVFA` keys, as appropriate. - Android Studio 3.5.1 or later is required to build Android samples. - TrulyNatural SDK now requires Android [API level 18][api-levels] or later. - Android sample apps use `targetSdkVersion 28`. - Upgraded to Gradle version 5.4.1. - _sample/c/Makefile_ notes the `SNSR_EDIT` macro change required when cross-compiling the samples. - **Fixed** - Crash when attempting to use _spot-voicegenie-enUS-6.3.0.snsr_ in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0) of [tpl-spot-select](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-select). - Edge-case segmentation fault in [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-sequential). - If files listed in the in-vocabulary or out-of-vocabulary lists were not readable, the [spot-eval-batch](https://doc.sensory.com/tnl/7.8/tools/snsr-eval-batch.md#snsr-eval-batch) utility did not process all files in these lists. - [spot-eval-batch](https://doc.sensory.com/tnl/7.8/tools/snsr-eval-batch.md#snsr-eval-batch) logged in-vocabulary false accepts with the `INVFX` tag instead of `INVTX`, as specified in the documentation. - [spot-eval-batch](https://doc.sensory.com/tnl/7.8/tools/snsr-eval-batch.md#snsr-eval-batch) did not count in-vocabulary false accepts when the `-u` flag was specified. These FAs were logged, though. ## 6.11.0 (2019-08-14) - **Added** - _tpl-spot-select-1.0.0.snsr,_ see [tpl-spot-select](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-select). - Support for linking with only a subset of available SDK capabilities. This can significantly reduce application code size. + [model:ids](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#modelids), [SUBSET_INIT](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_subset_init). + [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) supports generating custom initialization code with scope limited to example models. + New [faq](https://doc.sensory.com/tnl/7.8/faq.md#faq) entry: [How can I reduce application code size?](https://doc.sensory.com/tnl/7.8/faq.md#reduce-code-size) - Exhaustive list of all possible values of [reason](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#reason). - Support for `arm64e` on iOS. - _(tnl)_ [phone-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phone-iterator) support for [LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type). - _(tnl)_ [search.frame-nota](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#searchframe-nota) setting for [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition). - **Changed** - Model streams are de-duplicated and now contain only one instance of each unique object. In some use cases this can lead to significant model size (and therefore RAM use) reductions. - _udt-enUS-2.88.9.7.snsr_ with improved enrollment quality checking. - _sample/android/enroll-udt/_ sample enrollment app shows the current enrollment and the number of enrollments required. - **Fixed** - Java `static` member functions were not in the documentation index. - **Security** - The [spot-data.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data.md#spot-datac) sample read beyond the end of the input buffer on the last audio block processed. - _(tnl)_ Fixed possible out-of-bounds heap write when building a custom recognizer from a list of phrases, [phrases-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#phrases-stream) ## 6.10.0 (2019-07-15) - **Added** - [reset](https://doc.sensory.com/tnl/7.8/api/inference.md#reset). - Enrolled fixed trigger model for use with TrulySecure Speaker Verification post-processing: _eft-hbg-enUS-23.0.0.8-tssv.snsr._ - Voice Genie spotter with improved performance: _spot-voicegenie-enUS-6.3.0.snsr._ - Enrolled fixed trigger with lower imposter accept rate: _eft-hbg-enUS-23.0.0.8.snsr._ - DSP library (for creating embedded spotter models) version 6.1.4. - [spot-eval-batch](https://doc.sensory.com/tnl/7.8/tools/snsr-eval-batch.md#snsr-eval-batch) utility writes the default log file to the current directory, instead of the directory the spotter model is in. - _(tnl)_ _tpl-spot-vad-lvcsr-3.1.0.snsr_ adds support for threaded LVCSR recognizers that run slower than real-time. - _(tnl)_ Broad-domain speech-to-text with improved accuracy: _lvcsr-broad-enUS-1.2.0.snsr._ - _(tnl)_ Support for running LVCSR recognizers from code space. - **Fixed** - Java documentation: [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require) throws an `IllegalArgumentException,` not an `IOException.` - _(tnl)_ When an LVCSR recognizer was used with a VAD, [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) would occasionally not be invoked. ## 6.9.0 (2019-05-20) - **Added** - [spot-eval-batch](https://doc.sensory.com/tnl/7.8/tools/snsr-eval-batch.md#snsr-eval-batch) utility. - Support for running spotter models from code space. On platforms where code runs directly from ROM this reduces RAM requirements. + New function: [fromCode](https://doc.sensory.com/tnl/7.8/api/io.md#fromcode). + New [DataFormat](https://doc.sensory.com/tnl/7.8/api/inference.md#dataformat) value, [SOURCE](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_source). - Option `-c` in [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) converts a model to read-only C code. - Support for deep-learned VAD, usable without a preceding phrase spotter. This improves speech segmentation accuracy over the energy-only models. + _vad-ml-3.0.0.snsr_ + _(tnl)_ _tpl-vad-lvcsr-3.0.0.snr_ - **Changed** - Samples [spot-data.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data.md#spot-datac) and [spot-data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data-stream.md#spot-data-streamc) run the spotter models from code space. - Updated FAQ entry: [What if the spotter consumes too much memory?](https://doc.sensory.com/tnl/7.8/faq.md#low-ram) - _udt-enUS-2.88.7.7.snsr_ with improved enrollment quality checking. - **Fixed** - _(tnl)_ _tpl-spot-vad-lvcsr-3.0.0.snsr_ and _tpl-spot-vad-lvcsr-2.0.1.snsr_ produced unexpected results when used with [include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence) `= 1`. ## 6.8.0 (2019-03-29) - **Added** - Experimental support for a deep-learned VAD. This improves speech segmentation accuracy. + _tpl-spot-vad-3.0.0.snsr_ + _(tnl)_ _tpl-spot-vad-lvcsr-3.0.0.snr_ - **Changed** - Voice Genie spotter with improved performance: _spot-voicegenie-enUS-6.2.0.snsr._ - Updated energy-based VAD models with improved speech segmentation performance: + _tpl-spot-vad-2.0.1.snsr_ + _tpl-spot-vad-lvcsr-2.0.1.snsr_ + _vad-lvcsr-2.0.1.snsr_ + _vad-energy-2.0.1.snsr_ - DSP library (for creating embedded spotter models) version 6.1.3. - [models](https://doc.sensory.com/tnl/7.8/models/index.md#models) promoted out of the Overview documentation page. - Java [forEach](https://doc.sensory.com/tnl/7.8/api/inference.md#foreach) method no longer throws an `Exception` for return codes [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end), [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop), [SKIP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_skip), [REPEAT](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_repeat), and [TIMED_OUT](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_timed_out). - **Fixed** - Upgraded to Gradle version 5.2.1 for compatibility with Java 11. - Java [setString](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) with the [delete-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#delete-user) key threw a `RuntimeException` if the [^done](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#done) handler returned a code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok). - [faq](https://doc.sensory.com/tnl/7.8/faq.md#faq) still contained references to the `-m` [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) command-line option that was replaced by `-f`. - Some noisy enrollment recordings with context were mistakenly rejected. - _(tnl)_ Using weights on variables in a grammar caused an `abort()` on Windows. - **Security** - Fixed possible heap buffer overrun when loading a corrupted task model file. ## 6.7.0 (2019-02-06) - **Added** - New [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) settings: [id](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#id), [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator). - _spot-voicegenie-enUS-6.1.0-m.snsr._ This is a fixed trigger for the phrase "Voice Genie" in US English with improved performance. Note that this does not support [confidence-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#confidence-score). - [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) and [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) support a new `-f` command-line option that loads a file into a model setting. - UDT model for use with TrulySecure Speaker Verification post-processing: _udt-enUS-5.1.1.7-tssv.snsr._ - _(tnl)_ Ability to build recognizers from a grammar specification, or from a list of alternate phrases. + New settings: [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream) and [phrases-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#phrases-stream) + See [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) for additional detail. - _(tnl)_ New model that supports building a custom recognizer in US English: _lvcsr-build-enUS-1.0.0.snsr._ - Source code for the macOS and iOS SnsrStream audio capture implementation: [aqs-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/aqs-stream.md#aqs-streamc) and [aqs-stream.h](https://doc.sensory.com/tnl/7.8/api/sample/c/aqs-stream.md#aqs-streamc). - Windows 64-bit MinGW library, in _lib/x86_64-windows-mingw/libsnsr.a_ - **Changed** - _spot-eval_ tool renamed to [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) to better reflect its usage as a general-purpose model evaluator. This is a name change only, [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) behavior is compatible with the previous _spot-eval_ tool. The source code for [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) is available as [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-evalc). - Removing an enrolled user with [delete-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#delete-user) will invoke the [^done](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#done) handler. Also see the updated documentation for [model-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#model-stream). - DSP library (for creating embedded spotter models) version 6.1.2. - [sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sample-count) returns 53 usable bits, regardless of the width of `size_t`. This value previously wrapped after 74.5 hours on 32-bit machines. - Spotter models updated to support [id](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#id) and [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator): + _spot-hbg-enUS-1.3.0-m.snsr_ + _spot-music-enUS-1.1.0-m.snsr_ + _spot-voicegenie-enUS-1.1.0-m.snsr_ + _tpl-spot-debug-1.2.0.snsr_ + _tpl-spot-dynop-1.1.0.snsr_ + _tpl-spot-sequential-1.1.0.snsr_ + _tpl-spot-vad-1.1.0.snsr_ + _(tnl)_ _tpl-spot-vad-lvcsr-1.2.0.snsr_ - Enrollment models updated to support [id](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#id) and [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator) on enrolled models, and to improve enrollment error checks: + _eft-hbg-enUS-23.0.0.7.snsr_ + _udt-enUS-2.88.6.7.snsr_ + _udt-enUS-5.1.1.7.snsr_ + _udt-enUS-12.0.10.7.snsr_ - ARM libraries support threaded recognizers, and require linking with _pthread_ and _rt_. - **Removed** - The `-m` command-line option in [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit). Use the new `-f` option instead. - **Fixed** - Corner case where the VAD could fail with `to-index (xxx) must be <= last-index (yyy)` if the input stream ended while in a speech region. - Retrieving [audio-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#audio-stream) from a VAD failed after 74.5 hours of continuous processing on machines with 32-bit `size_t`. - Some enrollment recordings with context were mistakenly rejected. - A race condition that could lead to unexpected errors when running sequential recognizers simultaneously on multiple threads. - _tpl-spot-vad-*_ templates occasionally reported a start point after the actual start of speech. - [set](https://doc.sensory.com/tnl/7.8/api/inference.md#set) failed to report an error when a string value exceeded the maximum length (255 characters). - _(tnl)_ Poor LVCSR recognition performance in utterances containing long pauses. - _(tnl)_ When an LVCSR recognizer was used with a VAD, [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) would occasionally not be invoked. ## 6.6.0 (2018-11-28) - **Added** - Alpha-level support for fixed triggers with continuous background user enrollment, for improved false-accept performance. + [cache-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#cache-file). + Contact your [Sensory Sales](https://doc.sensory.com/tnl/7.8/contact.md#contact) representative for details. - Enrolled spotters with support for [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point). - New UDT model: _udt-enUS-2.88.6.6.snsr,_ with improved false-accept and impostor accept performance. Supports five different [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point)s. - **Changed** - Android Studio 3.2.1 or later is required to build Android samples. - Android sample apps target API level 28, and request runtime permissions where supported. - Xcode 10.1 or later is required to build iOS sample code. - Updated task models: + _tpl-spot-vad-1.0.5.snsr_, see [tpl-spot-vad](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad). + _vad-energy-1.0.6.snsr_, see [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type). + _(tnl)_ _tpl-spot-vad-lvcsr-1.1.1.snsr_ supports [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) and [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator), see [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr). + _(tnl)_ _tpl-vad-lvcsr-1.1.1.snsr_, see [tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-vad-lvcsr). - **Removed** - _udt-enUS-2.88.5.5.snsr_, superseded by _udt-enUS-2.88.6.6.snsr_. - **Fixed** - VAD models rejected short single words as noise. - _tpl-spot-vad-*_ templates had poor speech end-point detection when used with automatic gain control. - NEON vector acceleration was not used on AArch64 architectures. ## 6.5.2 (2018-10-24) - **Added** - Support for improved performance in new enrolled fixed-trigger models. - Improved descriptions of [^enrolled](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#enrolled) and [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted). - **Fixed** - Returning [SKIP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_skip) from [^pass](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#pass) did not discard the enrollment. ## 6.5.1 (2018-10-03) - **Changed** - DSP library (for creating embedded spotter models) version 6.0.1. - **Fixed** - Enrolled fixed-trigger models for release 6.5.0 could fail with a segmentation fault on poor quality enrollment recordings. - Java [save](https://doc.sensory.com/tnl/7.8/api/inference.md#save) method `#!java public SnsrSession save(SnsrDataFormat format, SnsrStream outputStream)` failed with a memory error. ## 6.5.0 (2018-09-21) - **Added** - Models and library artifacts are published to the local Maven repository (`mavenLocal()`) during installation. - New settings: [accel-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#accel-info), [lvcsr](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#lvcsr), and [task-type-and-version-list](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type-and-version-list). - _spot-voicegenie-enUS-1.0.0-m.snsr_. This is a fixed trigger for the phrase "Voice Genie" in US English that supports [confidence-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#confidence-score). - New UDT model: _udt-enUS-2.88.5.5.snsr,_ with improved false-accept and impostor accept performance. - FAQ section: [How do I improve wake word performance?](https://doc.sensory.com/tnl/7.8/faq.md#improve-performance) - Android `#!java static SnsrStream fromAudioDevice(int device, int sampleRate)` method allows audio source selection. - _(tnl)_ [LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type) task type. - **Changed** - [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require) supports [task-type-and-version-list](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type-and-version-list). - Added a note to _push-spot.c_ warning against use with threaded models. - Increased _push-spot.c_ ring buffer size to ten seconds. - Java `SnsrStream` has `protected` scope, to avoid accidental use. New [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) instances must be created using the static [constructor](https://doc.sensory.com/tnl/7.8/api/io.md#constructors) methods. - Android library artifact names are either `thf` or `tnl` to distinguish between TrulyHandsfree and TrulyNatural SDKs. For example: `com.sensory.speech.snsr:tnl:6.5.0@aar` and `com.sensory.speech.snsr:thf:6.5.0@aar` - [spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert) throws a more informative error message if a model cannot be converted to a deeply embedded format. - Reduced the result latency incurred for internally multi-threaded spotter models. - [library-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#library-info) includes [accel-info](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#accel-info) status. - _tpl-spot-debug-1.1.0.snsr_ supports [include-model](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-model). - Increased [model-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#model-stream) scope. This now continues to be available after the [^done](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#done) handler has returned. - Enrollment audio quality requirements relaxed in new models: _eft-hbg-enUS-23.0.0.5.snsr_, _udt-enUS-12.0.10.5.snsr_, and _udt-enUS-5.1.1.5.snsr_. - _(tnl)_ Updated task models, with a new [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type), [lvcsr](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#lvcsr). The templates improve the audio hand-off from the VAD to the LVCSR recognizer. + _lvcsr-broad-enUS-1.1.0.snsr_: Broad-domain speech-to-text. + _tpl-spot-vad-lvcsr-1.1.0.snsr_: Template for LVCSR on VAD-segmented audio, gated by a phrase spotter. See [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr). + _tpl-vad-lvcs-1.1.0.snsr_: Template for LVCSR on VAD-segmented audio. See [tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-vad-lvcsr). + _tpl-spot-debug-1.1.0.snsr_: Supports [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot) tasks built from [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr) and [tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-vad-lvcsr) templates. - _(tnl)_ If [show-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#show-silence) is `0`, empty LVCSR results were not reported via [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) and [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial). These handlers are now invoked with a [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) value of `""`. - **Removed** - UDT model: _udt-enUS-12.6.21.0.snsr,_ superseded by _udt-enUS-2.88.5.5.snsr._ - **Fixed** - [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) mistakenly returned [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok) after previously stopped by a callback in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0) or slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1). - [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) mistakenly returned [ELEMENT_API_VIOLATION](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) after successive calls with an empty [<-audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-pcm-out) stream. - Aberrant task behavior if an event callback returned [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end) when using live audio. - A task saved to file after either [audio-stream-from](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-stream-from) or [audio-stream-to](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-stream-to) had been set failed to load. - Certain non-enrolled spotters mistakenly returned values other than `1.0` for [sv-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sv-score). - _(tnl)_ LVCSR time-alignments ([begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), [begin-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-sample), [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms), [end-sample](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-sample)) wrapped after 524 seconds. ## 6.4.0 (2018-07-28) - **Added** - [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config). - [tearDown](https://doc.sensory.com/tnl/7.8/api/heap.md#teardown). - [IS_TRULYHANDSFREE](https://doc.sensory.com/tnl/7.8/api/constants.md#is_trulyhandsfree) and [IS_TRULYNATURAL](https://doc.sensory.com/tnl/7.8/api/constants.md#is_trulynatural). - FAQ section: [Is this SDK thread-safe?](https://doc.sensory.com/tnl/7.8/faq.md#thread-safe) - **Fixed** - [noise-energy](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#noise-energy), [signal-energy](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#signal-energy), and [snr](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#snr) returned `1024` for the second and subsequent spotted phrases, when used with [tpl-spot-vad](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad). - [dup](https://doc.sensory.com/tnl/7.8/api/inference.md#dup) failed to clone models larger than 1 MiB. Limit increased to 1 GiB. - Retrieving [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text), [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms), and [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms) **after** iterating over [phrase-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phrase-iterator), [word-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#word-iterator), or [phone-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#phone-iterator) could lead to an invalid memory access. - A race condition when simultaneously loading models in separate threads could lead to unexpected behavior. Affected release 6.3.0 only. - _(tnl)_ _lvcsr-broad-enUS-1.0.0.snsr_ and certain custom models had unbounded heap use. ## 6.3.0 (2018-06-24) - **Added** - FAQ section: [How do I spot phrases on a Real-Time Operating System (RTOS) with a custom audio driver and no filesystem?](https://doc.sensory.com/tnl/7.8/faq.md#program-for-rtos) - Sample code: [data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/data-stream.md#data-streamc), [data-stream.h](https://doc.sensory.com/tnl/7.8/api/sample/c/data-stream.md#data-streamc), [spot-data.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data.md#spot-datac), and [spot-data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data-stream.md#spot-data-streamc). - Include Android samples in documentation: [enrolltrigger/Enroll.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-enroll), [enrolltrigger/PhraseSpot.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-phrasespot), and [spotdebug/PhraseSpot.java](https://doc.sensory.com/tnl/7.8/api/sample/android/snsr-debug.md#sd-phrasespot). - _(tnl)_ Support for LVCSR models. - _(tnl)_ New task models: + _lvcsr-broad-enUS-1.0.0.snsr_: Broad-domain speech-to-text. + _tpl-spot-vad-lvcsr-1.0.0.snsr_: Template for LVCSR on VAD-segmented audio, gated by a phrase spotter. See [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr). + _tpl-vad-lvcs-1.0.0.snsr_: Template for LVCSR on VAD-segmented audio. See [tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-vad-lvcsr). - _(tnl)_ [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial), [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval), and [show-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#show-silence). - _(tnl)_ FAQ section: [How do I use Large Vocabulary Continuous Speech Recognition?](https://doc.sensory.com/tnl/7.8/faq.md#use-lvcsr) - **Changed** - _tpl-spot-dynop-1.1.0.snsr_ dynamic operating point selection template. - _spot-eval_ shows preliminary results, if available. - **Removed** - Android support for ARMv5 (armeabi), MIPS, and MIPS64. These are no longer supported by the [NDK][]. - **Fixed** - [available-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#available-point) always returns 0 when used with _tpl-spot-dynop-1.0.0.snsr_. - An enrollment context saved with [RUNTIME](https://doc.sensory.com/tnl/7.8/api/inference.md#fm_runtime) after using [delete-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#delete-user) to remove a user still included the removed user. Saving the context from the [^enrolled](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#enrolled) or [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted) worked as expected. ## 6.2.0 (2018-05-15) - **Added** - Support for spotters that reject phrases similar to the target. ## 6.1.0 (2018-05-02) - **Added** - Support for spotters that utilize multiple CPU cores. - Support for half-rate spotters, which reduce CPU usage. - Support for **v4** spotters with runtime-selectable [operating points](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point). - _tpl-spot-dynop-1.0.0.snsr_ dynamic operating point selection template with new configuration settings: + [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms) + [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point) + [threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#threshold) - New FAQ section: [How do I improve the user experience for wake words in poor audio environments?](https://doc.sensory.com/tnl/7.8/faq.md#improve-user-experience) - New UDT model: _udt-enUS-12.6.21.0.snsr_, with improved false-accept and impostor accept performance. - **Changed** - [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) changes are allowed in running spotters. For example, from within a [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) callback. - DSP library (for creating embedded spotter models) version 4.4.3. - **Fixed** - _tpl-spot-vad-1.0.4.snsr_ used with [include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence) `== 1` could lose part of the spotted phrase. - _vad-energy-1.0.5.snsr_ replaces _vad-energy-1.0.4.snsr_ to address error raised after a successful end-point detection. - C sample code does not compile without warning when using a C++ compiler. ## 6.0.0 (2018-03-21) - **Added** - `PhraseSpot` iOS sample application. See [iOS examples](https://doc.sensory.com/tnl/7.8/api/sample/ios/index.md#ios-examples). - **Changed** - Documentation sets split by API language binding. - Linux libraries compiled with `-fno-stack-protector` and `-D_FORTIFY_SOURCE=0` to improve compatibility with additional GLIBC variants: _aarch64-linux-gnu_, _arm-linux-gnueabi_, _arm-linux-gnueabihf_, _i686-linux-gnu_, and _x86_64-linux-gnu_. - [require](https://doc.sensory.com/tnl/7.8/api/inference.md#require) supports version ranges. - Task models with [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version) set to `1.0.0`: _eft-hbg-enUS-23.0.0.4.snsr_, _spot-hbg-enUS-1.2.4-m.snsr_, _spot-music-enUS-1.0.4-m.snsr_, _tpl-spot-concurrent-1.0.4.snsr_, _tpl-spot-debug-1.0.4.snsr_, _tpl-spot-sequential-1.0.4.snsr_, _tpl-spot-vad-1.0.4.snsr_, _udt-enUS-12.0.10.4.snsr_, and _udt-enUS-5.1.1.4.snsr_. - New FAQ section: [Can I use models from the beta releases?](https://doc.sensory.com/tnl/7.8/faq.md#beta-model-compatibility) - **Removed** - `SNSR_TECH_LEVEL` and `Snsr.TECH_LEVEL`. Use SDK version instead. - **Fixed** - `aarch64-linux-gnu` library does not support ALSA recording. [api-levels]: https://en.wikipedia.org/wiki/Android_version_history "Android version history and API levels" [NDK]: https://developer.android.com/ndk/downloads/revision_history "Android NDK Revision History" [UUID]: https://en.wikipedia.org/wiki/Universally_unique_identifier "Universally unique identifier" *[ALSA]: Advanced Linux Sound Architecture *[API]: Application Programming Interface *[AQS]: Audio Queue Services, Apple's audio capture API on Darwin / macOS *[EFT]: Enrolled Fixed Trigger: fixed wake words adapted to a speaker to improve accuracy *[FR]: False Reject: the recognizer did not trigger when the target phrase was spoken *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[MIPS]: Million Instructions Per Second *[NLU]: Natural Language Understanding model *[RAM]: Random Access Memory *[ROM]: Read-Only Memory, typically nonvolatile flash memory *[RTOS]: Real-Time Operating System *[SDK]: Software Development Kit *[THF]: TrulyHandsfree, Sensory's wake word and command recognition technology *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets *[VAD]: Voice Activity Detector --- source_path: "contact.md" canonical_url: "https://doc.sensory.com/tnl/7.8/contact/" --- # Contact information Get in touch with Sensory. ## Technical Support Send support questions and bug reports to [techsupport@sensory.com](mailto:techsupport@sensory.com). ## Sales Please contact your sales representative, or our [Sales Offices](https://doc.sensory.com/tnl/7.8/contact.md#sales). ## Address [Sensory, Inc.](https://sensory.com/)
[3150 De La Cruz Blvd., Suite 120
Santa Clara, CA 95054](https://maps.google.com/maps?q=3150+De+La+Cruz+Blvd,+Suite+120,+Santa+Clara,+CA+95054)
USA
Tel: (408) 625-3300 *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "faq.md" canonical_url: "https://doc.sensory.com/tnl/7.8/faq/" --- # Frequently Asked Questions - [Recipes](#faq-recipes) — push audio, capture speech after a wake word, UI-thread callbacks. - [Concepts](#faq-concepts) — thread safety, model types, LVCSR, RTOS integration. - [Performance](#faq-performance) — code size, memory, wake-word tuning. - [Troubleshooting](#faq-troubleshooting) — debug audio, model compatibility, display issues. ## Recipes Short answers for tasks that come right after [Your first program](https://doc.sensory.com/tnl/7.8/getting-started/your-first-program.md#your-first-program). Follow the links for full samples and API detail. ### How do I push audio? Use **push** mode when your app owns the audio path — for example a custom driver, an RTOS without a blocking read API, or fixed-size buffers from another thread. The library does not read the microphone for you; you pass each chunk to [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) on [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm). Contrast with **pull** mode on [Your first program](https://doc.sensory.com/tnl/7.8/getting-started/your-first-program.md#your-first-program): there you attach [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) (or a file stream) and call [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run). 1. [new](https://doc.sensory.com/tnl/7.8/api/inference.md#new) / `new SnsrSession()` — empty [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session). 2. [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) your `.snsr` model. 3. [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) for [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) and any other [events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) you need. 4. Loop: read a chunk from your driver (often 10–20 ms of 16 kHz PCM), then `snsrPush(s, SNSR_SOURCE_AUDIO_PCM, buffer, nbytes)` (Java: `session.push(...)`). 5. When finished, call [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop) once to flush buffered audio, then [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release). Do **not** attach an input stream with [setStream](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) on [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm) in push mode — audio enters only through [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push). Handlers run on the thread that calls [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) (see [UI thread callbacks](https://doc.sensory.com/tnl/7.8/faq.md#ui-thread-callbacks)). **C/C++** ```c /* 15 ms @ 16 kHz mono 16-bit LE */ #define CHUNK 480 char pcm[CHUNK]; size_t n = myAudioRead(pcm, CHUNK); /* your driver */ snsrPush(s, SNSR_SOURCE_AUDIO_PCM, pcm, n); ``` **Java** ```java byte[] pcm = myAudioRead(); /* your driver */ session.push(Snsr.SOURCE_AUDIO_PCM, pcm); ``` **Also see these related items:** [API overview § Push mode](https://doc.sensory.com/tnl/7.8/api/overview.md#processing-modes), [push-audio.c](https://doc.sensory.com/tnl/7.8/api/sample/c/push-audio.md#push-audioc), [spot-data.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data.md#spot-datac) ### How do I capture the audio that fired the wake word? Use a **composed** spotter + VAD model so the SDK segments speech after the trigger and writes PCM to an output stream. 1. Build or download a pipeline model — for example compose [tpl-spot-vad](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad) with [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) (see [tpl-spot-vad-type](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad.md#tpl-spot-vad-type)), or use a pre-built spot+VAD `.snsr` from your SDK tree. 2. [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) the pipeline into a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session). 3. Attach live input on [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm) ([fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) or your push loop). 4. Attach a WAV (or buffer) sink on [<-audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm): `snsrSetStream(s, SNSR_SINK_AUDIO_PCM, snsrStreamFromFileName("out.wav", "w"))` (wrap with [fromAudioStream](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiostream) if needed — see [live-segment.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-segment.md#live-segmentc)). 5. Register [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) to note the spot, and [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end) (or [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit)) to know when the following utterance ended; stop [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) or return [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop) from the endpoint handler. 6. Optional: set [include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence) to `1` (or [include-wake-word-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-wake-word-audio)) if the saved clip should include the wake word audio, not only the command. The Java sample [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudiojava) runs this flow with Gradle; C uses the same settings in [live-segment.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-segment.md#live-segmentc). Read [begin-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#begin-ms) / [end-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#end-ms) in the endpoint handler if you need timestamps without writing a file. ### How do I wire callbacks into a UI thread? [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) [events](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) and [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) handlers run on the **same thread** that calls [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) or [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) — not on your UI thread. Keep handlers short: copy what you need, then return. Update the UI from your toolkit's main thread. | Platform | Pattern | |----------|---------| | **Android** | Run [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) / [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push) on a worker thread or `HandlerThread`; post UI work with `Handler` / `runOnUiThread`. See [snsr-debug](https://doc.sensory.com/tnl/7.8/api/sample/android/snsr-debug.md#snsr-debug) (`PhraseSpot` worker thread). | | **iOS (C API)** | Call [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) from a background `DispatchQueue`; update SwiftUI/UIKit on the main actor. See [PhraseSpot](https://doc.sensory.com/tnl/7.8/api/sample/ios/phrasespot.md#ios-ps). | | **Java desktop** | Run recognition off the EDT; use `SwingUtilities.invokeLater` (or equivalent) for UI updates. | The one cross-thread exception: you may call [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop) from another thread to unblock a [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) that is waiting on live audio ([thread-safe](https://doc.sensory.com/tnl/7.8/faq.md#thread-safe) FAQ). Never share a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) or [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handle across threads without your own lock; create one session per recognition worker. **Also see these related items:** [Your first program](https://doc.sensory.com/tnl/7.8/getting-started/your-first-program.md#your-first-program) (platform tabs), [push](https://doc.sensory.com/tnl/7.8/api/inference.md#push), [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spotc) ## Concepts ### Is this SDK thread-safe? Yes, as long as [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) and [Stream](https://doc.sensory.com/tnl/7.8/api/io.md#stream) handles are not shared between threads. The number of handles per thread is limited only by system resources. If you need to share one of these handles across threads, you _must_ provide application-level mutual exclusion locking. **Note:** There is just one exception to this requirement: You may call [stop](https://doc.sensory.com/tnl/7.8/api/inference.md#stop) on a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle from a different thread than the one [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) is executing on. If you replace the dynamic memory allocator with [config](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) and [CONFIG_ALLOC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc) the new allocator implementation must be thread-safe. Use [allocLock](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloclock) to add thread-safety to an allocator that is not. ### What is a Command Set? Command sets are phrase spotters with more than one phrase. These are frequently tuned to have a limited [listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window). Command set recognizers have [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) `==` [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot) and can be used as a drop-in replacement for any wake word. No code changes are required. Most command sets are tuned for use after an always-listening keyword spotter. The [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-sequential.md#tpl-spot-sequential-type) template provides a convenient way to build such a model. ### Can I run two wake word models at the same time? Yes, see [tpl-spot-concurrent](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-concurrent.md#tpl-spot-concurrent-type). ### Can I create a trigger-to-search model? Yes. Create a new phrase spot model from the [tpl-spot-vad](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad.md#tpl-spot-vad-type) template. ### How do I enroll Fixed Trigger models? EFT models use the same API, and follow the same enrollment recipe as UDT models. Replace the UDT model _udt-universal-3.67.1.0.snsr_ in any of the examples with an EFT enrollment model such as _eft-hbg-enUS-23.0.0.9.snsr_. ### How do I improve the user experience for wake words in poor audio environments? Use a spotter model with Smart Wake Word support. See [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point) and [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms). ### How do I spot phrases on a Real-Time Operating System (RTOS) with a custom audio driver and no filesystem? You should implement a new custom stream similar to [data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/data-stream.md#data-streamc) which is used in [spot-data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data-stream.md#spot-data-streamc). This shows how to make a custom stream which should encapsulate your audio driver functionality, and which your [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) can pull data from. An alternative is pushing data onto a stream. See [spot-data.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data.md#spot-datac). You can take data chunks of any size (perhaps provided by your audio driver) and push them onto a stream to be read by an [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session). ### How do I use Large Vocabulary Continuous Speech Recognition? _(tnl)_ This TrulyNatural release includes three different ways of running a speech-to-text recognizer: [without audio segmentation](https://doc.sensory.com/tnl/7.8/faq.md#lvcsr-no-vad), [with VAD audio segmentation](https://doc.sensory.com/tnl/7.8/faq.md#lvcsr-vad), and with [wake word gated VAD](https://doc.sensory.com/tnl/7.8/faq.md#lvcsr-spot-vad). **Note:** The [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) callback only happens when a VAD endpoint is detected, or the end of the input stream is reached. For applications with live audio recognition, LVCSR recognizers should always be used with a VAD, such as [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-opt-spot-vad-lvcsr.md#tpl-opt-spot-vad-lvcsr-type), [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad-lvcsr.md#tpl-spot-vad-lvcsr-type), or [tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-vad-lvcsr.md#tpl-vad-lvcsr-type). #### LVCSR without audio segmentation The _stt-enUS-automotive-medium-2.3.15-pnc.snsr_ model included in this distribution is a generic broad-domain US English speech-to-text recognizer with a special domain focus on automotive commands. ```console % bin/snsr-eval -t model/stt-enUS-automotive-medium-2.3.15-pnc.snsr \ data/enrollments/armadillo-1-3-c.wav P 40 200 Im P 80 640 Armadillo P 120 1120 Armadillo playing P 120 1520 Armadillo play marsa P 120 1880 Armadillo play more songs by P 120 2320 Armadillo play more songs by this art P 120 2600 Armadillo play more songs by this artist P 120 2640 Armadillo play more songs by this artist NLU intent: music_player (0.9849) = armadillo play more songs by this artist 120 2640 Armadillo play more songs by this artist. ``` Preliminary or partial results above are prefixed with `P`. Suppress these by setting the [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval) to `0`: ```console % bin/snsr-eval -t model/stt-enUS-automotive-medium-2.3.15-pnc.snsr \ -s partial-result-interval=0 \ data/enrollments/armadillo-1-3-c.wav NLU intent: music_player (0.9849) = armadillo play more songs by this artist 120 2640 Armadillo play more songs by this artist. ``` #### LVCSR with VAD-segmented audio Large vocabulary recognizers perform better when used with a Voice Activity Detector that removes extraneous leading and trailing silence. Create such a VAD-lvcsr model using the [tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-vad-lvcsr.md#tpl-vad-lvcsr-type) template: ```console % bin/snsr-edit -t model/tpl-vad-lvcsr-3.17.0.snsr \ -f 0 model/stt-enUS-automotive-medium-2.3.15-pnc.snsr \ -o vad-stt-enUS-automotive-medium-pnc.snsr ``` Evaluate using [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval): ```console % bin/snsr-eval -t vad-stt-enUS-automotive-medium-pnc.snsr \ data/enrollments/armadillo-1-0-c.wav P 230 830 Armadilla P 270 1150 Armadillo, eight P 310 1630 Armadillo, eighteen percent P 310 1910 Armadillo. Eighteen percent of s P 310 2430 Armadillo, eighteen percent of six hundred P 310 2790 Armadillo, eighteen percent of six hundred and forty P 310 3150 Armadillo, eighteen percent of six hundred forty three NLU intent: no_command (0.9765) = armadillo eighteen percent of 643 NLU entity: number (0.9564) = 643 310 3190 Armadillo, eighteen percent of six hundred forty three. ``` #### LVCSR following a wake word The [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad-lvcsr.md#tpl-spot-vad-lvcsr-type) template provides a way to start a large-vocabulary recognizer with a spotted wake word. In this example we'll enroll a wake-word, then use the enrolled spotter with the broad-domain recognizer. Create an enrolled spotter for "jackalope": ```console % spot-enroll -vt model/udt-universal-3.67.1.0.snsr \ +jackalope \ data/enrollments/jackalope-1-0.wav \ data/enrollments/jackalope-1-1.wav \ data/enrollments/jackalope-1-4.wav \ data/enrollments/jackalope-1-3.wav Adapting: 100% complete. Enrolled model saved to "enrolled-sv.snsr" ``` Combine the enrolled spotter and the broad-domain recognizer using the [tpl-spot-vad-lvcsr-3.23.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr) template: ```console % snsr-edit -vt model/tpl-spot-vad-lvcsr-3.23.0.snsr \ -f 0 enrolled-sv.snsr \ -f 1 model/stt-enUS-automotive-medium-2.3.15-pnc.snsr \ -s include-leading-silence=1 \ -o jackalope-stt-enUS-automotive-medium-pnc.snsr Saved edited model to "jackalope-stt-enUS-automotive-medium-pnc.snsr". ``` Evaluate using [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval). Note that the wake word is not included in the LVCSR transcription. ```console % snsr-eval -t jackalope-stt-enUS-automotive-medium-pnc.snsr \ data/enrollments/jackalope-1-2-c.wav P 1050 1530 Directions P 1050 1930 Directions to sus P 1050 2370 Directions to Susan's house P 1050 2530 Directions to Susan's house NLU intent: navigation (0.9973) = directions to susan's house NLU entity: navigation_location (0.9811) = susan's house 1050 2530 Directions to Susan's house. ``` #### LVCSR with lightweight NLU parsing The included LVCSR and STT models support a lightweight natural language mark-up. This can significantly simplify application code that has to interpret recognition results. See [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) for a description of the grammar syntax. ##### NLU with custom grammar recognizers ```console % snsr-eval -t model/lvcsr-build-enUS-12.13.1-5MB.snsr \ -s partial-result-interval=0 \ -f grammar-stream data/grammars/enrollments-nlu-slot.txt \ data/enrollments/armadillo-1-4-c.wav NLU intent: avcontrol (0) = record a video NLU entity: action (0) = record NLU entity: type (0) = video 435 1995 armadillo record a video ``` ##### NLU with broad-domain recognizers In TrulyNatural [v6.16.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.16.0) and later, NLU parsing is a separate processing step that occurs after the [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) event. NLU parsing includes a special `.` symbol that matches any input word. This allows crafting of more robust island parsers that can be used with free-form recognition results from a broad-domain model. This small example detects a small set of microwave control commands using _lvcsr-lib-enUS-1.2.0.snsr_. **Note:** The _stt-enUS-automotive-medium-2.3.15-pnc.snsr_ model includes machine-learned NLU processing for automotive command tasks. If you use [nlu-grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#nlu-grammar-stream) with this model the grammar-based NLU will override the machine-learned NLU parsing. **`tiny-microwave.nlu`** ``` # Microwave command NLU post-processor grammar # tiny-microwave.nlu # power level setting, "fifty percent". don't capture optional "power" power = ~s.percent power?; # timer duration, "two minutes and ten seconds" duration = ~s.timer; # defrost command: the word "defrost" followed by # zero or more power or duration values, both captured # .* matches any input word sequence defrost = defrost ( .* ({power} | {duration}) .* )* ; # default action matches any input and discards it default = .:*; # set clock time: the word "clock" or "time" followed by # a time ("seven twenty nine pm"). # ignore spurious words before and after the time specification clock = (clock | time) .* {time ~s.time} .*; # list of all the actions we've defined, captured action = {defrost} | {clock} | {default}; # match any one of the actions, ignoring unknown words before # and after nlu = .* $action .* ; ``` Build and run a recognizer with live input. ``` % snsr-eval -vat model/stt-enUS-automotive-medium-2.3.15-pnc.snsr \ -t model/lvcsr-lib-enUS-1.2.0.snsr \ -f nlu-grammar-stream tiny-microwave.nlu \ -s partial-result-interval=0 Using live audio from default capture device. ^C to stop. # "Defrost my soup for 15 minutes at 30% power" Using live audio from default capture device. ^C to stop. 4035 8835 [^end] VAD speech region. NLU intent: defrost (0) = defrost my soup for 15 minutes at thirty percent power NLU entity: duration (0) = 15 minutes NLU entity: power (0) = thirty percent power 4310 8470 (0.4805) Defrost my soup for fifteen minutes at thirty percent power. # "Could you set the clock to 3:43 pm?" 48165 51810 [^end] VAD speech region. NLU intent: clock (0) = clock to 15:43 NLU entity: time (0) = 15:43 48360 51360 (0.163) Could you set the clock to three? Forty three P? M. ``` ##### Dealing with NLU parse ambiguity It is possible to get more than one valid parse result if the NLU grammar introduces ambiguity. The NLU processor scores these alternates and returns the best hypotheses in order, up to [nlu-match-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-match-max). During the [^nlu-slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-slot) callback, [nlu-match-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-match-count) reports the number of alternates available, with [nlu-match-index](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-match-index) the current alternate. [nlu-match-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-match-max) defaults to `1` for best compatibility with earlier releases. **Warning:** Resolving NLU ambiguity can be expensive both in terms of computation and heap memory use. Avoid using patterns that match arbitrary input in multiple ways: ``` g = {left .*} {right .*} ; ``` This example uses two NLU grammars: _system.nlu_ for basic functionality provided by a product, and _app.nlu_ to extend NLU processing for a plug-in application. If the application duplicates some of the system NLU actions we need these reported for the system to take appropriate action. **`system.nlu`** ``` # system.nlu volume = volume: {volume-level ~s.percent}; preset = preset: number:? ~s.number-integer-0-9; system = {volume} | {preset}; # :/-0.1 adds a small weight bias towards the ~app class, so # ~app will outscore $system for identical matches plugin = :/-0.1 ~app; action = {system} | {plugin}; nlu = $action ; ``` **`app.nlu`** ``` # app.nlu media-control = ~s.control.media; preset = preset: ( one | two | three | four | five ); nlu = {media-control} | {preset}; ``` Build and run a recognizer with live input. Set the value for [nlu-match-max](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#nlu-match-max) to allow up to ten alternate matches. ```console % snsr-eval -vvat model/stt-enUS-automotive-medium-2.3.15-pnc.snsr \ -t model/lvcsr-lib-enUS-1.2.0.snsr \ -f nlu-grammar-stream system.nlu \ -f nlu-grammar-stream.app app.nlu \ -s partial-result-interval=0 \ -s nlu-match-max=10 Using live audio from default capture device. ^C to stop. # "volume 50%" # in system grammar 5235 [^begin] 4710 6645 [^end] VAD speech region. NLU intent: system (0) = fifty percent NLU entity: volume.volume-level (0) = fifty percent NLU 1/1 nlu-slot-value.system (0) = { volume { volume-level fifty percent } } NLU 1/1 nlu-slot-value.system.volume (0) = { volume-level fifty percent } NLU 1/1 nlu-slot-value.system.volume.volume-level (0) = fifty percent phrase: 4990 6270 (0.8939) Volume. Fifty percent. words: 4990 5470 (0.8955) Volume. 5550 5870 (0.9986) Fifty 5950 6270 (0.9996) percent. # "fast forward" # in plugin grammar 17070 [^begin] 16545 17940 [^end] VAD speech region. NLU intent: plugin (0) = fast forward NLU entity: media-control (0) = fast forward NLU 1/1 nlu-slot-value.plugin (0) = { media-control fast forward } NLU 1/1 nlu-slot-value.plugin.media-control (0) = fast forward phrase: 16860 17540 (0.7646) Fast forward. words: 16860 17100 (0.9913) Fast 17220 17540 (0.7713) forward. # "preset 5" # in both system and plugin grammars, but plugin reported first # due to the weight bias 22290 [^begin] 21765 23325 [^end] VAD speech region. NLU intent: plugin (0) = five NLU entity: preset (0) = five NLU 1/2 nlu-slot-value.plugin (0) = { preset five } NLU 1/2 nlu-slot-value.plugin.preset (0) = five NLU intent: system (0) = five NLU entity: preset (0) = five NLU 2/2 nlu-slot-value.system (0) = { preset five } NLU 2/2 nlu-slot-value.system.preset (0) = five phrase: 22040 22920 (0.9432) Preset. Five. words: 22040 22480 (0.9443) Preset. 22680 22920 (0.9988) Five. ``` ##### How do I take action on an NLU result? You can think of an intent as specifying which function or method you should call to perform an action. Entities identify parts of the utterance that include additional detail. For example, a `call_contact` intent might have a `contact_name` entity that specifies who to call. - Register a handler for [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent) - In this handler, + Retrieve [nlu-intent-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-name) as a string. + Map this intent name to an action. Do this by comparing the intent name to all valid intent names for which you want to perform an action. + If the matched action requires additional data, retrieve the expected [nlu-entity-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-value) by name. + Call a function (specified by the intent value) with zero or more arguments specified by the entity values. + Return from the intent event handler with [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok). ## Performance ### How can I reduce application code size? By default, any applications linked against the TrulyNatural library can run any model (_.snsr_) file supported by the library. You can reduce the overall code size of an application by limiting the library capabilities to only the models of interest. Use [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) with the `-i` flag to create custom initialization code that references only the modules used by the models included in your application. For example: ```console % snsr-edit -v -i -t spot-voicegenie-enUS-6.5.1-m.snsr Output written to "snsr-custom-init.c". ``` This creates a custom initialization file, _snsr-custom-init.c_, that references only the code modules used by _spot-voicegenie-enUS-6.5.1-m.snsr_. Add this file to your application, and compile with `-DSNSR_USE_SUBSET` This will replace all calls to [snsrNew](https://doc.sensory.com/tnl/7.8/api/inference.md#new) with a variant that initializes only the required modules. You can further reduce code size by linking at the function instead of the module level. See [sample/c/Makefile](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#makefile) for compiler and linker flag examples (`-ffunction-sections`). ### Can I avoid dynamic memory allocation? You can avoid all calls to `malloc()`, `realloc()`, and `free()` by replacing the memory allocator with [CONFIG_ALLOC](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_alloc). For embedded use we recommend [allocTLSF](https://doc.sensory.com/tnl/7.8/api/library-config.md#alloctlsf). Use this with one or more pre-defined read-write memory segments that remain valid for the lifetime of the application. ### How do I improve wake word performance? [Contact Sensory](https://doc.sensory.com/tnl/7.8/contact.md#contact) if interested in pursuing these customizations. There may be additional cost involved. Not all combinations may be possible depending on platform and trigger specification. #### How to measure real-time factor and MIPS * To measure the real-time factor, time how long it takes to run the spotter over a long audio file. Then, real time factor = (run time in seconds) / (length of audio in seconds). * To measure the MIPS on your device, use a profiler like perf when running the spotter over an audio file. Then, MIPS = (No. of instructions) / (length of audio in seconds * 1000000). #### What if the spotter runs too slow, or consumes too many cycles? You could explore one of these options to see an improvement: Try [multi-threaded](https://doc.sensory.com/tnl/7.8/faq.md#multi-threaded), [frame-stacked](https://doc.sensory.com/tnl/7.8/faq.md#frame-stacked), or [little-big](https://doc.sensory.com/tnl/7.8/faq.md#little-big) spotters. You may also want to get a smaller spotter model, which uses less CPU (in proportion to its size) with a small reduction in FA and FR performance. Contact Sensory to see if these options are right for you. #### What if the spotter consumes too much memory? 1. Contact Sensory for a smaller model. 1. If your platform runs code directly from ROM, consider converting the spotter to compiled-in code. This will run from read-only code space, and reduce heap requirements. Use the [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) tool to create a C source file from any spotter model. See [fromCode](https://doc.sensory.com/tnl/7.8/api/io.md#fromcode) and examples [spot-data-stream.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data-stream.md#spot-data-streamc) and [spot-data.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-data.md#spot-datac) #### What is a little-big spotter? A little-big spotter does sequential recognition by first running a low-power spotter. When this spots, it re-processes the audio with a high-power state-of-the-art spotter. This reduces average CPU cycles (and hence power) required to run a spotter with a small increase in latency. This one combined model has the behavior of a high-power spotter. #### What is a frame-stacked spotter? Frame stacked spotters reduce the CPU load by 30-45%, in exchange for a small reduction in FA and FR performance. The resolution of time alignments is also reduced by a factor of two. #### What is a multi-threaded spotter? Multi-threaded spotters speed up execution on CPUs with more than one core. ## Troubleshooting ### How do I diagnose wake word audio issues? Create a new wake word model from the [tpl-spot-debug](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-debug.md#tpl-spot-debug-type) template. See the [notes](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-debug.md#tpl-spot-debug-type-notes) and [example](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-debug.md#tpl-spot-debug-type-examples). ### Can I use models from the beta releases? Yes. This release is compatible with older models, but it requires a modification to the task requirement sanity checks. Use `"~0.5.0 || 1.0.0"` instead of `"1.0.0"`, for example: **C/C++** ```c snsrRequire(session, SNSR_TASK_VERSION, "~0.5.0 || 1.0.0"); ``` **Java** ```java session.require(Snsr.TASK_VERSION, "~0.5.0 || 1.0.0"); ``` The models included in the [v6.0.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.0.0) release use [task-version](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-version) values of `1.0.0`. This makes these models incompatible with 5.0.0-beta releases. ### How do I display international characters in results? On Windows systems, when using Sensory STT models with [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) [v7.3.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.3.0) or earlier, international characters such as Chinese (zhCN) may appear as garbled symbols such as "Σ╜á σÑ╜ σÉù" instead of correct [UTF-8][] characters "您 好 吗". This is a display encoding issue, not an issue with the recognition output itself. Solution Options 1. Set Console Code Page to UTF-8 Before running snsr-eval.exe, run the following command in the Windows Command Prompt: ``` chcp 65001 ``` This sets the console's code page to UTF-8, enabling correct display of international characters. `snsr-eval` [v7.4.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.4.0) and later does this before writing any output. 2. Enable System-Wide UTF-8 Support (Recommended for Long-Term Use) - Open Settings > Time & Language > Administrative Language Settings - Under Change system locale, check: "**Beta: Use Unicode UTF-8 for worldwide language support**" - Save your changes and restart your computer to apply them This setting ensures that all applications and the console will handle UTF-8 properly by default. [UTF-8]: https://en.wikipedia.org/wiki/UTF-8 *[API]: Application Programming Interface *[EFT]: Enrolled Fixed Trigger: fixed wake words adapted to a speaker to improve accuracy *[FA]: False Accept: the recognizer triggered when the target phrase was not spoken *[FR]: False Reject: the recognizer did not trigger when the target phrase was spoken *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[MIPS]: Million Instructions Per Second *[NLU]: Natural Language Understanding model *[PNC]: Punctuation and Capitalization, an STT model variant that emits cased text with punctuation *[ROM]: Read-Only Memory, typically nonvolatile flash memory *[RTOS]: Real-Time Operating System *[SDK]: Software Development Kit *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets *[VAD]: Voice Activity Detector --- source_path: "getting-started/index.md" canonical_url: "https://doc.sensory.com/tnl/7.8/getting-started/" --- # Getting started with command-line tools This walk-through helps you get started with TrulyNatural concepts and the command-line tools (`snsr-eval`, `snsr-edit`, and related utilities). **Ready to embed in your own app?:** See [Your first program](https://doc.sensory.com/tnl/7.8/getting-started/your-first-program.md#your-first-program) for a hands-on Session API walk-through with platform tabs for **C** (CMake), **Java** (Gradle), **Android**, and **iOS** (C API from Swift via a bridging header). **Looking for sample code?:** See [C](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#c-examples), [Java](https://doc.sensory.com/tnl/7.8/api/sample/java/index.md#java-examples), [Android](https://doc.sensory.com/tnl/7.8/api/sample/android/index.md#android-examples), and [iOS](https://doc.sensory.com/tnl/7.8/api/sample/ios/index.md#ios-examples) in the [API reference](https://doc.sensory.com/tnl/7.8/api/index.md#api-reference) section. ## Prerequisites The paths below assume the default online documentation install location, _$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9_. If you installed the SDK elsewhere, replace that prefix with your SDK installation directory. Offline SDK documentation uses the actual installed path. 1. Install the TrulyNatural SDK using the provided installer executable. 2. Open a terminal with a command-line prompt. 3. Add _$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/bin_ to your shell `PATH` variable, and change your working directory to _$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9_ **Configure your shell environment** ```shell PATH=${PATH}:$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/bin cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9 ``` ## Wake words 1. Let's start with running a simple wake word on live audio input. The [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) utility can run all recognition and VAD model types. Use the `-t` (_task_) flag to specify the path to the wake word model. Start `snsr-eval` and say "voice genie" a number of times: ```console % snsr-eval -t model/spot-voicegenie-enUS-6.5.1-m.snsr 1275 1920 voicegenie 5070 5730 voicegenie 10395 10980 voicegenie ^C ``` The output shows the start and end times in ms since the start of the recording, and the phrase the key word spotter detected. `snsr-eval` runs until you interrupt it with `^C`. The [spot-voicegenie-enUS-6.5.1-m.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#spot-voicegenie-enUS) model file includes everything needed to run this wake word, including reasonable default settings. For wake words, there is one configuration option that you might want to adjust: [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point), which controls the recognition sensitivity. You can do this on the command-line with the `-s` option: ```console % snsr-eval -t model/spot-voicegenie-enUS-6.5.1-m.snsr -s operating-point=21 1080 1605 voicegenie 2610 3180 voicegenie 5460 5970 voicegenie ^C ``` Increase [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) output verbosity with one or more `-v` flags: ```console % snsr-eval -vt model/spot-voicegenie-enUS-6.5.1-m.snsr Using live audio from default capture device. ^C to stop. 1410 1995 (0.999) voicegenie ^C % snsr-eval -vvt model/spot-voicegenie-enUS-6.5.1-m.snsr Using live audio from default capture device. ^C to stop. Using operating point 8. Available operating points: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21. Available vocabulary: 1: "voicegenie" phrase: 495 1020 (0.9951) voicegenie words: 495 1020 (0.9951) voicegenie ^C ``` The value between the parentheses is the recognition [score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#score). You can also reduce the output verbosity with one or more `-l` flags. `snsr-eval -ll` reports only the recognition result, which makes it suitable for scripted batch testing. **Note:** type: tip Run [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval), or any of the [command-line tools](https://doc.sensory.com/tnl/7.8/tools/index.md#command-line-tools) without arguments to see a brief usage summary and a list of available options. 2. To recognize pre-recorded audio, specify an audio file in either [RIFF WAV][] format or as a binary file containing audio samples and no header. Most models require 16-bit LPCM encoding sampled at 16 kHz. ```console % snsr-eval -t model/spot-voicegenie-enUS-6.5.1-m.snsr \ data/audio/voice-genie-set-cruise-control.wav 2310 2910 voicegenie ``` `snsr-eval` ends once it has processed the entire file. If you specify multiple files `snsr-eval` concatenates the files in order and evaluates the model on the result. Recognition timestamps reflect this concatenation. ```console % snsr-eval -t model/spot-voicegenie-enUS-6.5.1-m.snsr \ data/audio/voice-genie-set-cruise-control.wav \ data/audio/voice-genie-set-cruise-control.wav 2310 2910 voicegenie 9075 9645 voicegenie ``` 3. [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) also runs [command sets](https://doc.sensory.com/tnl/7.8/faq.md#use-command-set). These are keyword spotters with more than one active word or phrase, optimized for a low false reject rate. Let's inspect the [sample music control](https://doc.sensory.com/tnl/7.8/models/index.md#spot-music-enUS) model vocabulary: ```console % snsr-eval -vvt model/spot-music-enUS-1.2.0-m.snsr /dev/null Using operating point 17. Available operating points: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20. Available vocabulary: 1: "play_music" 2: "previous_song" 3: "stop_music" 4: "next_song" 5: "pause_music" ``` Command sets work just like wake words: ```console % snsr-eval -t model/spot-music-enUS-1.2.0-m.snsr \ data/audio/voice-genie-music.wav 5160 5865 play_music 8055 8790 next_song 14820 15705 stop_music ``` 4. Running an [adapting wake word](https://doc.sensory.com/tnl/7.8/models/types/ca.md#ca-type) uses the same recipe as regular wake words: ```console % snsr-eval -vt model/ca-voicegenie-enUS-1.1.0.snsr Using live audio from default capture device. ^C to stop. [^adapt-started] on worker thread 8295 8790 (1 sv) voice_genie [^adapt-started] on worker thread 15645 16245 (1 sv) voice_genie 16515 [^adapted] 16515 [^new-user] user1/voice_genie [^adapt-started] on worker thread 20445 21060 (0.9678 sv) user1/voice_genie 21225 [^adapted] ^C ``` Note how the result changes once the model has adapted to your speech. If you have a second speaker say "voice genie" a couple of times you should see `user2/voice_genie` for their utterances. The model adaptations do not persist and will be lost when the model is reloaded. We can address that by specifying a [cache-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#cache-file) to hold these. Say "voice genie" a number of times, then stop `snsr-eval` with `^C`: ```console % snsr-eval -vt model/ca-voicegenie-enUS-1.1.0.snsr \ -s cache-file=voice-genie.cache Using live audio from default capture device. ^C to stop. [^adapt-started] on worker thread 1485 2070 (1 sv) voice_genie [^adapt-started] on worker thread 4740 5355 (1 sv) voice_genie 5460 [^adapted] 5460 [^new-user] user1/voice_genie [^adapt-started] on worker thread 9285 9855 (0.9951 sv) user1/voice_genie 10140 [^adapted] ^C ``` `snsr-eval` loads _voice-genie.cache_ when restarting. Note that the very first result already includes the `user1/voice_genie` result: ```console % snsr-eval -vt model/ca-voicegenie-enUS-1.1.0.snsr \ -s cache-file=voice-genie.cache Using live audio from default capture device. ^C to stop. [^adapt-started] on worker thread 1185 1815 (0.9971 sv) user1/voice_genie 2085 [^adapted] ^C ``` ## Wake word enrollment EFT models adapt a specific wake word phrase to a speaker's voice. UDT models create new wake words for arbitrary phrases from a handful of speaker-specific recordings. 1. Let's start with UDT. The [spot-enroll](https://doc.sensory.com/tnl/7.8/tools/spot-enroll.md#spot-enroll) utility does EFT and UDT enrollment from recordings. Most models require four recordings of the same phrase for optimal performance. UDT models are less likely to trigger on the same phrase said by another speaker. **Enroll three phrases into a single model** ```console % spot-enroll -vt model/udt-universal-3.67.1.0.snsr \ -o udt-kws.snsr \ +armadillo-1 data/enrollments/armadillo-1-{0,1,2,3}.wav \ +armadillo-6 data/enrollments/armadillo-6-{0,1,2,3}.wav \ +jackalope-1 data/enrollments/jackalope-1-{0,1,2,3}.wav \ +jackalope-4 data/enrollments/jackalope-4-{0,1,2,3}.wav \ +terminator-2 data/enrollments/terminator-2-{0,1,2,3}.wav \ +terminator-6 data/enrollments/terminator-6-{0,1,2,3}.wav Adapting: 100% complete. Enrolled model saved to "udt-kws.snsr" ``` We've just created a new `udt-kws.snsr` wake word model that spots three different phrases with two unique speakers per phrase. We can run the model with [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval). We'll use different recordings than the ones used for enrollment: ```console % snsr-eval -t udt-kws.snsr \ data/enrollments/armadillo-1-0-c.wav \ data/enrollments/armadillo-6-0.wav \ data/enrollments/jackalope-1-0-c.wav \ data/enrollments/jackalope-4-0.wav \ data/enrollments/terminator-2-0.wav \ data/enrollments/terminator-6-0.wav 330 945 armadillo-1 4485 5265 armadillo-6 6795 7320 jackalope-1 10365 10890 jackalope-4 13245 13950 terminator-2 15510 16215 terminator-6 ``` The model identifies the phrases and the speakers correctly. 2. EFT models use the same tools and API for enrollment as UDT. We'll use [live-enroll](https://doc.sensory.com/tnl/7.8/tools/live-enroll.md#live-enroll) in this example. This is the interactive version of [spot-enroll](https://doc.sensory.com/tnl/7.8/tools/spot-enroll.md#spot-enroll), the main difference being that it prompts to repeat recordings that aren't usable instead of reporting an enrollment error. Run the example below, then say "hello blue genie" when prompted. ```console % live-enroll -vt model/eft-hbg-enUS-23.0.0.9.snsr \ -o eft-hbg.snsr +user-1 Say the enrollment phrase (1/4) for "user-1" Recording: 4.29 s Preliminary enrollment checks passed. Say the enrollment phrase (2/4) for "user-1" Recording: 3.23 s Preliminary enrollment checks passed. Say the enrollment phrase (3/4) for "user-1" with context, for example: " will it rain tomorrow?" Recording: 3.15 s Preliminary enrollment checks passed. Say the enrollment phrase (4/4) for "user-1" with context, for example: " will it rain tomorrow?" Recording: 3.90 s Preliminary enrollment checks passed. Adapting: 100% complete. Enrolled model saved to "eft-hbg.snsr" ``` As before, test with [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval): ```console % snsr-eval -t eft-hbg.snsr Using live audio from default capture device. ^C to stop. 675 1500 (0.8921 sv) user-1/HBG 3480 4500 (0.8245 sv) user-1/HBG 7020 8160 (0.877 sv) user-1/HBG ^C ``` The value between the parentheses is the [sv-score](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#sv-score). ## Templates [Templates](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) are models that add new behaviors to [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type), [lvcsr](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type), and [stt](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type) models via composition. Templates have _slots_ that we fill with models of the required type. 1. Let's say we would like to reduce false accepts of the music command set used above by requiring commands in it to be prefixed with a low false-accept wake word like "voice genie". We can do this with the [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-sequential.md#tpl-spot-sequential-type) template: ```console % snsr-eval -t model/tpl-spot-sequential-1.5.0.snsr \ -f 0 model/spot-voicegenie-enUS-6.5.1-m.snsr \ -f 1 model/spot-music-enUS-1.2.0-m.snsr \ data/audio/voice-genie-music.wav 5175 5865 play_music ``` `snsr-eval`'s `-f slot filename` option loads the named file into the specified slot. The [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-sequential.md#tpl-spot-sequential-type) documentation lists the slots the template supports, and the types of models it expects for these. As expected, the new recognizer spots only the command directly following "voice genie". [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) supports on-the-fly model composition, but what if we have code that already works with _spot-music-enUS-1.2.0-m.snsr_ that we don't want to modify? Enter [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit), which supports composition and [setting](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) changes and can save the result as a new, self-contained model: ```console % snsr-edit -vvt model/tpl-spot-sequential-1.5.0.snsr \ -o vg-music.snsr \ -f 0 model/spot-voicegenie-enUS-6.5.1-m.snsr \ -f 1 model/spot-music-enUS-1.2.0-m.snsr Loading "model/tpl-spot-sequential-1.5.0.snsr" as the template model. Loading "model/spot-voicegenie-enUS-6.5.1-m.snsr" into setting "0". Loading "model/spot-music-enUS-1.2.0-m.snsr" into setting "1". Output written to "vg-music.snsr". % snsr-eval -t vg-music.snsr data/audio/voice-genie-music.wav 5175 5865 play_music ``` [tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-sequential.md#tpl-spot-sequential-type) has a [loop](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#loop) setting that changes behavior. Let's give that a try: ```console % snsr-eval -t vg-music.snsr -s loop=1 data/audio/voice-genie-music.wav 5175 5865 play_music 8055 8790 next_song ``` This recognizes the first two music commands, but not "stop music" as the gap between "next song" and "stop music" is more than the [listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window), which is five seconds: ``` % snsr-edit -t model/spot-music-enUS-1.2.0-m.snsr -q listen-window listen-window = 5 ``` 2. We can run two keyword spotters simultaneously with [tpl-spot-concurrent](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-concurrent.md#tpl-spot-concurrent-type): ```console % snsr-eval -t model/tpl-spot-concurrent-1.5.0.snsr \ -f 0 model/spot-voicegenie-enUS-6.5.1-m.snsr \ -f 1 model/spot-music-enUS-1.2.0-m.snsr \ data/audio/voice-genie-music.wav 4485 5085 voicegenie 5160 5865 play_music 8055 8790 next_song 14820 15705 stop_music ``` ## Speech To Text _(stt)_ TrulyNatural STT includes support for modern transformer-based end-to-end recognizers suitable for transcription tasks. 1. STT models use the same tools and API as wake words. Let's run a sample audio file through [stt-enUS-automotive-medium-2.3.15-pnc.snsr ](https://doc.sensory.com/tnl/7.8/models/index.md#stt-enUS-automotive-medium) with [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval): ```console % snsr-eval -t model/stt-enUS-automotive-medium-2.3.15-pnc.snsr \ data/audio/voice-genie-set-cruise-control.wav P 2040 2960 God Boice jeni P 2240 3560 Voice. Genie said the creek P 2240 3960 Voice. Genie set the cruise control P 2240 4200 Voice. Genie set the cruise control to P 2240 4720 Voice. Genie set the cruise control to further P 2240 5200 Voice. Genie set the cruise control to fifty five. Mrs P 2240 5600 Voice Genie set the cruise control to fifty five miles back P 2240 5800 Voice Genie set the cruise control to fifty five miles per hour P 2240 5840 Voice Genie set the cruise control to fifty five miles per hour NLU intent: set_cruise_control (0.9969) = voice genie set the cruise control to 55 miles per hour NLU entity: number (0.9931) = 55 NLU entity: speed_unit (0.9942) = miles per hour 2240 5840 Voice Genie set the cruise control to fifty five miles per hour. ``` Partial or interim hypotheses are shown prefixed with `P`. These provide useful feedback for live transcription tasks, but are less interesting when recognizing from file. You can suppress them by setting [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval) `= 0`: ```console % snsr-eval -t model/stt-enUS-automotive-medium-2.3.15-pnc.snsr \ -s partial-result-interval=0 \ data/audio/voice-genie-set-cruise-control.wav NLU intent: set_cruise_control (0.9969) = voice genie set the cruise control to 55 miles per hour NLU entity: number (0.9931) = 55 NLU entity: speed_unit (0.9942) = miles per hour 2240 5840 Voice Genie set the cruise control to fifty five miles per hour. ``` 2. STT and LVCSR models only produce a final recognition hypothesis at end-of-file, or when a VAD signals that speech has ended. For convenience [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) has an `-a` option that adds the [tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-vad-lvcsr.md#tpl-vad-lvcsr-type) template if you're using live audio and specify an STT model that does not include a VAD. ```console % snsr-eval -lt model/stt-enUS-automotive-medium-2.3.15-pnc.snsr ERROR: With live audio LVCSR and STT models require a VAD. You can add one with the -a flag. % snsr-eval -alt model/stt-enUS-automotive-medium-2.3.15-pnc.snsr NLU intent: no_command (0.9995) = the quick brown fox jumped over the lazy dog's back The quick Brown Fox jumped over the lazy dog's back. ^C ``` Create a new model that includes a VAD: ```console % snsr-edit -vvo vad-stt.snsr \ -t model/tpl-vad-lvcsr-3.17.0.snsr \ -f 0 model/stt-enUS-automotive-medium-2.3.15-pnc.snsr Loading "model/tpl-vad-lvcsr-3.17.0.snsr" as the template model. Loading "model/stt-enUS-automotive-medium-2.3.15-pnc.snsr" into setting "0". Output written to "vad-stt.snsr". % snsr-eval -lt vad-stt.snsr NLU intent: no_command (0.9995) = the quick brown fox jumped over the lazy dog's back The quick Brown Fox jumped over the lazy dog's back. ``` 3. Creating an STT model that's gated by a wake word is also easy with [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-opt-spot-vad-lvcsr.md#tpl-opt-spot-vad-lvcsr-type): ```console % snsr-edit -vvo vg-vad-stt.snsr \ -t model/tpl-opt-spot-vad-lvcsr-1.28.0.snsr \ -f 0 model/spot-voicegenie-enUS-6.5.1-m.snsr \ -f 1 model/stt-enUS-automotive-medium-2.3.15-pnc.snsr \ -s include-wake-word-audio=1 Loading "model/tpl-opt-spot-vad-lvcsr-1.28.0.snsr" as the template model. Loading "model/spot-voicegenie-enUS-6.5.1-m.snsr" into setting "0". Loading "model/stt-enUS-automotive-medium-2.3.15-pnc.snsr" into setting "1". Output written to "vg-vad-stt.snsr". ``` [include-wake-word-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-wake-word-audio) `= 1` includes the wake word in the audio seen by the STT recognizer, but configures the STT to elide this from the recognition hypothesis. This improves recognition accuracy if there's no pause between the wake word and the STT command. **Test with snsr-eval** ```console % snsr-eval -lt vg-vad-stt.snsr \ data/audio/voice-genie-set-cruise-control.wav NLU intent: set_cruise_control (0.9968) = set the cruise control to 55 miles per hour NLU entity: number (0.9937) = 55 NLU entity: speed_unit (0.9936) = miles per hour Set the cruise control to fifty five miles per hour. ``` **Test with snsr-eval and live audio** ```console % snsr-eval -t vg-vad-stt.snsr P 7180 7340 Said P 7220 7860 Said the radio P 7220 8220 Set the radio tonight P 7260 8580 Set the radio to ninety one P 7260 9060 Set the radio to ninety one point. Three P 7260 9260 Set the radio to ninety one point. Five P 7260 9620 Set the radio to ninety one point. Five f NLU intent: set_radio (0.9674) = set the radio to 91.5 FM NLU entity: radio_station (0.9688) = 91.5 FM 7260 9860 Set the radio to ninety one point. Five F. M. ^C ``` ## LVCSR _(tnl)_ Use [Grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) for command and control tasks with small to medium sized vocabularies on devices that aren't powerful enough for STT. [VoiceHub](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub) provides a convenient interface for creating these models. 1. Let's build a model that recognizes the example audio files in _data/enrollments/_. We'll use a grammar file from _data/grammars/_: ```console % snsr-edit -vvo commands.snsr \ -t model/lvcsr-build-enUS-12.13.1-5MB.snsr \ -f grammar-stream data/grammars/enrollments-nlu-slot.txt \ -s partial-result-interval=0 Loading "model/lvcsr-build-enUS-12.13.1-5MB.snsr" as the template model. Loading "data/grammars/enrollments-nlu-slot.txt" into setting "grammar-stream". Output written to "commands.snsr". % snsr-eval -t commands.snsr data/enrollments/armadillo-1-0-c.wav NLU intent: calculate (0) = 18 percent of 643 NLU entity: percent (0) = 18 NLU entity: number (0) = 643 375 3195 armadillo 18 percent of 643 ``` We set [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream) to the contents of _data/grammars/enrollments-nlu-slot.txt_ to define which sentences the recognizer will accept, and [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval) `= 0` to suppress interim results. ### Details: _data/grammars/enrollments-nlu-slot.txt_ type: info ``` # LVCSR grammar specification for test utterances in data/enrollments/ # Includes lightweight NLU slot markup. # # In a tpl-spot-vad-lvcsr pipeline the prefix would be consumed by the spotter. prefix = armadillo | jackalope | terminator; # Numbers used in the intent rule below number = 18 | 643 | 20 | 6; # Places place = target | winco | susan's house | gas; # Dates date = friday | tomorrow | next week; # List of known utterances in the *-c.wav files. intent = {calculate {percent $number} percent of {number}} | {call call the nearest {place}} | {navigate how far away is {place}} | {avcontrol {action play} {type more} songs by this artist} | {avcontrol {action record} a {type video}} | {startTimer start a timer for {number} minutes {unit :minutes}} | {navigate i'm running low on {place}} | {calendar {action cancel} all my {type meetings} on {date}} | {navigate directions to {place}} | {messaging do i have any new texts {action :query} {type :texts}} | {calendar {type open} my calendar to {date}} | {alarm {type set} an alarm for {number} am {date}}; # Match the prefix and zero or one of the sentences. # and are sentence start and end markers that # match silence and small amounts of extraneous speech. g = $prefix $intent? ; ``` 2. Let's combine the wake word we [previously enrolled](https://doc.sensory.com/tnl/7.8/getting-started/index.md#qs-ww-enrollment) with this LVCSR model and [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-opt-spot-vad-lvcsr.md#tpl-opt-spot-vad-lvcsr-type): ```console % snsr-edit -vvo ww-commands.snsr \ -t model/tpl-opt-spot-vad-lvcsr-1.28.0.snsr \ -f 0 udt-kws.snsr \ -f 1 commands.snsr \ -s include-wake-word-audio=1 Loading "model/tpl-opt-spot-vad-lvcsr-1.28.0.snsr" as the template model. Loading "udt-kws.snsr" into setting "0". Loading "commands.snsr" into setting "1". Output written to "ww-commands.snsr". ``` And then run it over all the enrollment recordings: ```console % snsr-eval -t ww-commands.snsr data/enrollments/*-c.wav NLU intent: calculate (0) = 18 percent of 643 NLU entity: percent (0) = 18 NLU entity: number (0) = 643 375 3195 armadillo 18 percent of 643 NLU intent: call (0) = call the nearest target NLU entity: place (0) = target 4695 6360 armadillo call the nearest target NLU intent: navigate (0) = how far away is winco NLU entity: place (0) = winco 7680 9495 armadillo how far away is winco NLU intent: avcontrol (0) = record a video NLU entity: action (0) = record NLU entity: type (0) = video 14535 16095 armadillo record a video NLU intent: startTimer (0) = start a timer for 20 minutes minutes NLU entity: number (0) = 20 NLU entity: unit (0) = minutes 17640 19905 armadillo start a timer for 20 minutes minutes NLU intent: navigate (0) = i'm running low on gas NLU entity: place (0) = gas 21060 22935 jackalope i'm running low on gas NLU intent: calendar (0) = cancel all my meetings on friday NLU entity: action (0) = cancel NLU entity: type (0) = meetings NLU entity: date (0) = friday 24315 26655 jackalope cancel all my meetings on friday NLU intent: navigate (0) = directions to susan's house NLU entity: place (0) = susan's house 27915 30195 jackalope directions to susan's house NLU intent: messaging (0) = do i have any new texts query texts NLU entity: action (0) = query NLU entity: type (0) = texts 31500 33525 jackalope do i have any new texts query texts NLU intent: calendar (0) = open my calendar to next week NLU entity: type (0) = open NLU entity: date (0) = next week 34695 36975 jackalope open my calendar to next week NLU intent: alarm (0) = set an alarm for 6 am tomorrow NLU entity: type (0) = set NLU entity: number (0) = 6 NLU entity: date (0) = tomorrow 38160 40665 jackalope set an alarm for 6 am tomorrow ``` **Note:** type: note The doubled "minutes" in the `startTimer` line above is expected: the grammar rule `{startTimer start a timer for {number} minutes {unit :minutes}}` matches the spoken word "minutes" against the literal token, then the `{unit :minutes}` slot rewrites to a second "minutes" so the intent text and the `unit` entity carry the same canonical value. See the `:` rewrite operator described in the [grammar syntax reference](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-syntax) for details. [RIFF WAV]: https://en.wikipedia.org/wiki/WAV#RIFF_WAVE "Audio file format" *[API]: Application Programming Interface *[EFT]: Enrolled Fixed Trigger: fixed wake words adapted to a speaker to improve accuracy *[LPCM]: Linear pulse-code modulation *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[NLU]: Natural Language Understanding model *[PNC]: Punctuation and Capitalization, an STT model variant that emits cased text with punctuation *[SDK]: Software Development Kit *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[UDT]: User-Defined Trigger: enrolled wake words and command sets *[VAD]: Voice Activity Detector --- source_path: "getting-started/your-first-program.md" canonical_url: "https://doc.sensory.com/tnl/7.8/getting-started/your-first-program/" --- # Your first program If you followed [Command-line tools](https://doc.sensory.com/tnl/7.8/getting-started/index.md#getting-started), you already ran a wake word with [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval). This page shows the same Session API flow on each platform. The **C** tab is a full from-scratch walk-through: a new directory, a short program, CMake, and a run command. The **Java** tab does the same with Gradle in a new directory. **Android** and **iOS** show the same API steps, then how to try them using the shipping sample projects. Android uses the Java API; iOS calls the **C API** from Swift via a [bridging header][] (there is no separate Swift API). ## Prerequisites You need the same SDK setup as on the [Command-line tools](https://doc.sensory.com/tnl/7.8/getting-started/index.md#getting-started) page: 1. Install the TrulyNatural SDK using the provided installer. 2. Open a terminal. 3. Add _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/bin_ to your `PATH` (optional for this page, but useful for tools). **C/C++** - A C compiler and [CMake][] 3.10 or later (Linux, macOS, or Windows). - A microphone for live audio. - A phrase-spot model file, for example the voice genie model at _$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/model/spot-voicegenie-enUS-6.5.1-m.snsr_. **Java** - [JDK][] 17 or later and [Gradle][] 8.0 or later (or use a Gradle wrapper). - A microphone ([Java Audio][] capture via [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice)). - A phrase-spot `.snsr` file (same voice genie model path as the C tab). **Android** - [Android Studio][] or a command-line Android SDK install; device or emulator with microphone support. - To try the sample on this page you do **not** need to change sample source — only build and run [snsr-debug](https://doc.sensory.com/tnl/7.8/api/sample/android/snsr-debug.md#snsr-debug). **iOS** - [Xcode][] on macOS and a device or simulator with microphone access. - To try the sample on this page you do **not** need to change sample source — only open and run [PhraseSpot](https://doc.sensory.com/tnl/7.8/api/sample/ios/phrasespot.md#ios-ps). ## The program The program below mirrors the pull-mode recipe in [API overview](https://doc.sensory.com/tnl/7.8/api/overview.md#api-overview): create a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session), [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) a spotter model, attach live [audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), register a [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) handler, call [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run), then [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release). This is a **teaching sketch** (minimal error handling). The shipped sample [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spotc) adds timing in the callback, full [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) checks, and more. **C/C++** Create _first-spot.c_ with: ```c #include #include #include static SnsrRC resultEvent(SnsrSession s, const char *key, void *privateData) { const char *phrase; SnsrRC r; r = snsrGetString(s, SNSR_RES_TEXT, &phrase); if (r != SNSR_RC_OK) return r; printf("Spotted \"%s\".\n", phrase); return SNSR_RC_STOP; } int main(int argc, char *argv[]) { SnsrRC r; SnsrSession s; if (argc != 2) { fprintf(stderr, "usage: %s spotter-model\n", argv[0]); return 1; } snsrNew(&s); // (1)! snsrLoad(s, snsrStreamFromFileName(argv[1], "r")); // (2)! snsrSetStream(s, SNSR_SOURCE_AUDIO_PCM, snsrStreamFromAudioDevice(SNSR_ST_AF_DEFAULT)); // (3)! snsrSetHandler(s, SNSR_RESULT_EVENT, snsrCallback(resultEvent, NULL, NULL)); // (4)! r = snsrRun(s); // (5)! if (r != SNSR_RC_STOP) fprintf(stderr, "ERROR: %s\n", snsrErrorDetail(s)); // (6)! snsrRelease(s); // (7)! return 0; } ``` 1. [new](https://doc.sensory.com/tnl/7.8/api/inference.md#new) — allocate an empty [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) handle. 2. [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) the `.snsr` model from disk (pass a phrase-spot `.snsr` file, as on the [Command-line tools](https://doc.sensory.com/tnl/7.8/getting-started/index.md#getting-started) page). 3. [setStream](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) attaches live PCM from the default capture device ([fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice)). 4. [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) registers `resultEvent` on the [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) event ([callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback)). 5. [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) blocks until the handler returns [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop) or an error [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc). 6. On any code other than [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop), print [errorDetail](https://doc.sensory.com/tnl/7.8/api/inference.md#errordetail) to `stderr` (same pattern as [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spotc)). The handler propagates [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) errors from [getString](https://doc.sensory.com/tnl/7.8/api/inference.md#getters). 7. [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) frees the session and attached streams. **Java** Create _FirstSpot.java_ with: ```java import com.sensory.speech.snsr.Snsr; import com.sensory.speech.snsr.SnsrRC; import com.sensory.speech.snsr.SnsrSession; import com.sensory.speech.snsr.SnsrStream; public class FirstSpot { public static void main(String[] argv) throws Exception { if (argv.length != 1) { System.err.println("usage: FirstSpot spotter-model"); System.exit(1); } SnsrSession s = new SnsrSession(); // (1)! s.load(argv[0]) // (2)! .setStream(Snsr.SOURCE_AUDIO_PCM, SnsrStream.fromAudioDevice()) // (3)! .setHandler(Snsr.RESULT_EVENT, (ses, key) -> { // (4)! System.out.println("Spotted \"" + ses.getString(Snsr.RES_TEXT) + "\"."); return SnsrRC.STOP; }); s.run(); // (5)! s.release(); // (6)! } } ``` 1. `new SnsrSession()` — empty [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) ([new](https://doc.sensory.com/tnl/7.8/api/inference.md#new)). 2. [load](https://doc.sensory.com/tnl/7.8/api/inference.md#load) the `.snsr` model from the path in `argv[0]`. 3. [setStream](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) with [fromAudioDevice](https://doc.sensory.com/tnl/7.8/api/io.md#fromaudiodevice) on the method chain. 4. [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) on [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result); return [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop) to end [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run). 5. [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) — pull-mode loop until the handler stops. 6. [release](https://doc.sensory.com/tnl/7.8/api/heap.md#release) the session. Look up signatures under the **Java** tabs on [Inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference) and [I/O](https://doc.sensory.com/tnl/7.8/api/io.md#input-and-output). The Java binding throws on failure instead of latched [RC](https://doc.sensory.com/tnl/7.8/api/inference.md#rc) codes (see [API overview § Language bindings](https://doc.sensory.com/tnl/7.8/api/overview.md#api-overview)). **Android** Uses the **Java** Session API — see **Java** tabs on [Inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference) for method details. The excerpt is the core wake-word-only flow in [snsr-debug](https://doc.sensory.com/tnl/7.8/api/sample/android/snsr-debug.md#snsr-debug); the shipping app also uses a worker thread, UI, and optional debug logging. ```java SnsrStream audio = SnsrStream.fromAudioDevice(); SnsrSession session = new SnsrSession(); session.load(assetToString(BuildConfig.TRIGGER_MODEL)) .setStream(Snsr.SOURCE_AUDIO_PCM, audio) .setHandler(Snsr.RESULT_EVENT, this); session.run(); ``` When you integrate into your own app, add `RECORD_AUDIO` to _AndroidManifest.xml_, use `SnsrStream.fromAudioDevice(int device, int sampleRate)` if you need a specific [MediaRecorder.AudioSource][], and follow [Integrate with your build § Android](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-android). **iOS** Calls the **C API** from Swift — look up `snsrLoad`, `snsrSetStream`, and related functions under the **C** tabs on [Inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference) and [I/O](https://doc.sensory.com/tnl/7.8/api/io.md#input-and-output). There is no Swift Session wrapper; [PhraseSpot](https://doc.sensory.com/tnl/7.8/api/sample/ios/phrasespot.md#ios-ps) uses a [bridging header][] and runs [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) on a background queue. ```swift // Excerpt — see PhraseSpot.swift for load(), UI, and AVAudioSession setup. snsrLoad(session, snsrStreamFromFileName(modelPath(modelName), "r")) snsrSetStream(session, SNSR_SOURCE_AUDIO_PCM, snsrStreamFromDefaultAudioDevice()) snsrSetHandler(session, SNSR_RESULT_EVENT, resultCallback) // snsrRun(session) — invoked on a background thread in the sample app. ``` ## Build and run **C/C++** Create a new directory anywhere (not under the SDK sample tree). The steps below assume _~/first-spot/_. 1. Save the program above as _first-spot.c_ in that directory. 2. Create _CMakeLists.txt_ in the same directory: ```cmake cmake_minimum_required(VERSION 3.10) project(first-spot C) list(APPEND CMAKE_MODULE_PATH "$ENV{HOME}/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9") include(SnsrLibrary) add_executable(first-spot first-spot.c) target_link_libraries(first-spot SnsrLibrary) ``` This follows [Integrate with your build](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-cmake) (CMake is the recommended approach on Linux, macOS, and Windows). Using GNU Make only? See [Integrate with your build § Make](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-make) and [C examples § Build with GNU Make](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#examples-make). 3. Configure and build: ```console cd ~/first-spot cmake -S . -B build cmake --build build ``` On Windows with Visual Studio generators, the executable may be under `build\Release\`. See [Integrate with your build](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-cmake) for toolchain notes. 4. Run the spotter. Say “voice genie” a few times: ```console ./build/first-spot $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/model/spot-voicegenie-enUS-6.5.1-m.snsr Spotted "voicegenie". ``` Press `^C` if the process does not exit after a spot (your handler should stop [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run) with [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop)). **Java** Create a new directory anywhere (not under the SDK sample tree). The steps below assume _~/first-spot-java/_. 1. Create the standard Gradle source layout and save _FirstSpot.java_ from the **Program** tab at _src/main/java/FirstSpot.java_ (default package). 2. Create _settings.gradle_ in the project root: ```gradle rootProject.name = 'first-spot' ``` 3. Create _build.gradle_ in the project root: ```gradle plugins { id 'java' id 'application' } // SDK root is the parent of m2repository (same layout as install.m2repo). def snsrMavenRepo = file("${System.getProperty('user.home')}/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/m2repository") def snsrRoot = snsrMavenRepo.parentFile repositories { maven { url = snsrMavenRepo.toURI() } } dependencies { implementation "com.sensory.speech.snsr:tnl:7.8.0-pre.0" } application { mainClass = 'FirstSpot' } def snsrNativeLib = { def os = System.getProperty('os.name').toLowerCase(java.util.Locale.ROOT) if (os.contains('mac')) { return new File(snsrRoot, 'lib/macos') } if (os.contains('linux')) { def machine = ['gcc', '-dumpmachine'].execute().text.trim() return new File(snsrRoot, "lib/${machine}") } if (os.contains('windows')) { return new File(snsrRoot, 'lib/x86_64-windows-msvc') } throw new GradleException( 'Set -Djava.library.path on the run task for your platform (see build-java).') }() tasks.named('run') { jvmArgs "-Djava.library.path=${snsrNativeLib.absolutePath}" } ``` Coordinates and JNI layout are described in [Integrate with your build § Java](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-java). 4. From the project root, configure and run: ```console cd ~/first-spot-java gradle run --args="$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/model/spot-voicegenie-enUS-6.5.1-m.snsr" ``` Gradle compiles everything under _src/main/java/_. If you see `ClassNotFoundException: FirstSpot`, check that _FirstSpot.java_ is in that folder, not the project root. If you see `UnsatisfiedLinkError: no SnsrJNI`, confirm the Maven URL ends in _m2repository_ so `snsrRoot` resolves to the SDK install (native libraries live in _lib/macos_ on macOS). 5. Say “voice genie”. Expect output similar to the C tab. ### Details: Without Gradle (`javac` / `java`) On Linux or macOS you can compile and run without a Gradle project. Set `SNSR_ROOT` to _$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9_, pick the Sensory JAR under `m2repository`, and point `java.library.path` at the native library directory for your OS (see [build-java](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-java)). These commands expect _FirstSpot.java_ in the current directory: ```console export SNSR_ROOT=$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9 SNSR_JAR=$(find "$SNSR_ROOT/m2repository" -name 'tnl-*.jar' \ ! -name '*-sources.jar' -print -quit) javac -cp "$SNSR_JAR" FirstSpot.java # macOS example: java -Djava.library.path="$SNSR_ROOT/lib/macos" \ -cp ".:$SNSR_JAR" FirstSpot \ "$SNSR_ROOT/model/spot-voicegenie-enUS-6.5.1-m.snsr" ``` On Linux, replace `lib/macos` with `lib/$(gcc -dumpmachine)`. **Android** ### Try the sample (no code changes) 1. Open _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/android/snsr-debug/_ in [Android Studio][] or use the command line (see [snsr-debug § Build](https://doc.sensory.com/tnl/7.8/api/sample/android/snsr-debug.md#sd-build)). 2. Connect a device or start an emulator with microphone support. 3. Build and install (no edits to sample sources): ```console cd ~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/android/snsr-debug ./gradlew installDebug ``` In Android Studio, press **Run** instead of the command above. 4. Launch **SnsrDebug**, choose **Wakeword**, press **TALK**, and say the trigger phrase (see [snsr-debug § Run](https://doc.sensory.com/tnl/7.8/api/sample/android/snsr-debug.md#sd-run)). ### Integrate in your own app Use the **Program** excerpt as a guide, then follow [Integrate with your build § Android](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-android) and the [Android examples](https://doc.sensory.com/tnl/7.8/api/sample/android/index.md#android-examples). A from-scratch Android walk-through is not duplicated here (manifest, AAR, assets, and UI threading are app-specific). **iOS** ### Try the sample (no code changes) 1. Open _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/sample/ios/PhraseSpot/PhraseSpot.xcodeproj_ in [Xcode][]. 2. Choose **Product → Run** on a device or simulator. Grant microphone access when prompted. Say the trigger phrase from [PhraseSpot § Instructions](https://doc.sensory.com/tnl/7.8/api/sample/ios/phrasespot.md#ios-ps-instructions). The project is already configured with `SNSR_ROOT`, bridging header, frameworks, and `NSMicrophoneUsageDescription` (see [build-ios](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-ios)). ### Integrate in your own app Use the **Program** excerpt and **C** API reference tabs, then follow [Integrate with your build § iOS](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-ios) and [iOS examples](https://doc.sensory.com/tnl/7.8/api/sample/ios/index.md#ios-examples). Creating a new Xcode target from scratch is integration work, not covered step-by-step on this page. ## What you just did 1. Created a [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) with [new](https://doc.sensory.com/tnl/7.8/api/inference.md#new). 2. [Loaded](https://doc.sensory.com/tnl/7.8/api/inference.md#load) a wake-word model. 3. Attached a live [audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm) source. 4. Registered a [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) [callback](https://doc.sensory.com/tnl/7.8/api/inference.md#callback) handler. 5. Ran pull-mode inference with [run](https://doc.sensory.com/tnl/7.8/api/inference.md#run). 6. [Released](https://doc.sensory.com/tnl/7.8/api/heap.md#release) the session. ## Next steps | Platform | Full sample | Look up API under | |----------|-------------|-------------------| | C | [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spotc) | C tabs on [Inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference) and [I/O](https://doc.sensory.com/tnl/7.8/api/io.md#input-and-output), … | | Java | [evalUDT.java](https://doc.sensory.com/tnl/7.8/api/sample/java/evalUDT.md#evaludtjava) | Java tabs on [Inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference) and [I/O](https://doc.sensory.com/tnl/7.8/api/io.md#input-and-output) | | Android | [snsr-debug](https://doc.sensory.com/tnl/7.8/api/sample/android/snsr-debug.md#snsr-debug) | Java tabs + [Android examples](https://doc.sensory.com/tnl/7.8/api/sample/android/index.md#android-examples) | | iOS | [PhraseSpot](https://doc.sensory.com/tnl/7.8/api/sample/ios/phrasespot.md#ios-ps) | **C** tabs + [Integrate with your build § iOS](https://doc.sensory.com/tnl/7.8/api/build-system.md#build-ios) | - [C examples](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#c-examples), [Java examples](https://doc.sensory.com/tnl/7.8/api/sample/java/index.md#java-examples), [Android examples](https://doc.sensory.com/tnl/7.8/api/sample/android/index.md#android-examples), [iOS examples](https://doc.sensory.com/tnl/7.8/api/sample/ios/index.md#ios-examples) — full samples, tests, and platform-specific build files. - [Inference](https://doc.sensory.com/tnl/7.8/api/inference.md#inference) quick reference — common [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) operations. - [FAQ § Recipes](https://doc.sensory.com/tnl/7.8/faq.md#push-audio-recipe) — push audio, capture speech after the wake word, and UI-thread callbacks (one screen each). ### Same program, composed models You do not need to change `first-spot.c` to run a multi-stage pipeline—only the model path on the command line. On [Command-line tools § Speech To Text](https://doc.sensory.com/tnl/7.8/getting-started/index.md#qs-stt) (_(stt)_), use [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) with a template such as [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-opt-spot-vad-lvcsr.md#tpl-opt-spot-vad-lvcsr-type) to build a wake-word-gated STT `.snsr` file, then run `./build/first-spot my-pipeline.snsr`. The same Session code loads any valid task file. [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spotc) *Instructions* step 3 shows this with the full sample (VAD + STT after the wake word). [Android Studio]: https://developer.android.com/studio/index.html "The official IDE for Android app development" [bridging header]: https://developer.apple.com/documentation/swift/importing-objective-c-into-swift "Importing Objective-C into Swift" [CMake]: https://cmake.org/ "CMake: A Powerful Software Build System" [Gradle]: https://gradle.org/install/ "Gradle Build Tool installation" [Java Audio]: https://docs.oracle.com/javase/tutorial/sound/capturing.html "Audio capturing in Java" [jdk]: https://adoptium.net "Java Development Kit" [MediaRecorder.AudioSource]: https://developer.android.com/reference/android/media/MediaRecorder.AudioSource "Android MediaRecorder.AudioSource" [Xcode]: https://developer.apple.com/xcode/ "Xcode enables you to develop, test, and distribute apps for all Apple platforms" *[API]: Application Programming Interface *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[SDK]: Software Development Kit *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[VAD]: Voice Activity Detector --- source_path: "index.md" canonical_url: "https://doc.sensory.com/tnl/7.8/" --- ![TrulyNatural SDK](assets/tnl.svg) # TrulyNatural SDK This is the reference documentation for version 7.8.0-pre.0+682.g276c2541e9 of [Sensory's][sensory] [TrulyHandsfree][thf], [TrulyNatural Lite][tnl-lite], and [TrulyNatural STT][tnl-stt] speech recognition SDKs. The TrulyNatural SDK is an on-device speech recognition stack for embedded systems, mobile apps, and desktop software. It runs locally — no network, no cloud — with a small RAM and CPU footprint, and ships with C and Java bindings. Use this site to evaluate the SDK, integrate it into an application, or look up an API or setting key while you build. **Coding agents:** Add [llms.txt](https://doc.sensory.com/tnl/7.8/llms.txt) to your editor's documentation index (for example **Cursor Settings → Docs**) so AI tools can use this doc set without extra configuration. See [Coding agents](agent-tools.md) for editor-specific setup and tips. - [**Command-line tools**](https://doc.sensory.com/tnl/7.8/getting-started/index.md#getting-started) - Install the SDK and run wake words, LVCSR, and STT with `snsr-eval` and related tools. - [**Your first program**](https://doc.sensory.com/tnl/7.8/getting-started/your-first-program.md#your-first-program) - Build a minimal wake-word app with the Session API (C, Java, Android, and iOS tabs). - [**Overview**](https://doc.sensory.com/tnl/7.8/reference/overview.md#ref-overview) - SDK variants, requirements, supported platforms, models, tools, and software license keys. - [**API reference**](https://doc.sensory.com/tnl/7.8/api/index.md#api-reference) - Using the programming interfaces. Includes sample code for [C](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#c-examples), [Java](https://doc.sensory.com/tnl/7.8/api/sample/java/index.md#java-examples), [Android](https://doc.sensory.com/tnl/7.8/api/sample/android/index.md#android-examples), and [iOS](https://doc.sensory.com/tnl/7.8/api/sample/ios/index.md#ios-examples). - [**Changelog**](https://doc.sensory.com/tnl/7.8/changes/index.md#v7-changes) - User-visible changes by SDK version. - [**FAQ**](https://doc.sensory.com/tnl/7.8/faq.md#faq) - Frequently Asked Questions. - [**Licenses**](https://doc.sensory.com/tnl/7.8/licenses/index.md#sensory-sdk-license) - Legal agreements. [Sensory]: https://sensory.com/ "Sensory, Inc. AI on the Edge & Beyond" [thf]: https://www.sensory.com/wake-word/ "Low Power Wake Words & Phrase Recognition Engine" [tnl-lite]: https://www.sensory.com/natural-language-understanding/ "Large Vocabulary Continuous Speech Recognition (LVCSR) with Dynamic Natural Language Understanding" [tnl-stt]: https://www.sensory.com/embedded-speech-to-text/ "Embedded Speech To Text" *[API]: Application Programming Interface *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[RAM]: Random Access Memory *[SDK]: Software Development Kit *[STT]: Speech To Text: transformers with language model and CTC decoding *[THF]: TrulyHandsfree, Sensory's wake word and command recognition technology *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "licenses/index.md" canonical_url: "https://doc.sensory.com/tnl/7.8/licenses/" --- # Sensory SDK license ## Sensory Inc. Software Developer's Kit ("SDK") **Note:** NOTICE TO USER: PLEASE READ THIS CONTRACT CAREFULLY. BY USING ALL OR ANY PORTION OF THE SDK YOU ACCEPT ALL THE TERMS AND CONDITIONS OF THIS LICENSE AGREEMENT, INCLUDING, IN PARTICULAR THE LIMITATIONS ON: USE CONTAINED IN SECTIONS 2, 3 AND 4; WARRANTY IN SECTION 7; AND LIABILITY IN SECTION 8. YOU AGREE THAT THIS LICENSE AGREEMENT IS ENFORCEABLE LIKE ANY WRITTEN NEGOTIATED AGREEMENT SIGNED BY YOU. IF YOU DO NOT AGREE, DO NOT USE THIS SDK. IF YOU ACQUIRED THE SDK ON TANGIBLE MEDIA (FOR EXAMPLE, CD-ROM) WITHOUT AN OPPORTUNITY TO REVIEW THIS LICENSE, AND YOU DO NOT ACCEPT THIS LICENSE AGREEMENT, YOU MAY NOT USE THE SDK. ### 1. Definitions "SDK" means all of the contents of the files, disk(s), CD-ROM(s) or other media with which this License Agreement is provided, including but not limited to (i) Sample Code; (ii) Header File Information; (iii) Redistributable Code, (iv) Documentation; and (v) any upgrades, modified versions, updates, and/or additions thereto, if any, provided to You by Sensory. "Sample Code" means sample software in source code format designated in the Documentation as "Sample Code." "Header File Information" means any header files (*.h files) supplied in connection with the SDK, including without limitation any related information detailing contents of header files. "Redistributable Code" means certain object code files designated in the Documentation as "Redistributable Code." "Documentation" means explanatory materials supplied with the SDK or made available online on Sensory public web pages related to the SDK. "Sensory" means Sensory. Inc., a California corporation, 3150 De La Cruz Blvd., Suite 120, Santa Clara, CA 95054. "Sensory Software" means the generally commercially available versions of Sensory TrulyNatural SDK. "Developer Programs" means Your application programs that are designed to function with Sensory Software products. "Developer," "You," and "Your" refer to any person or entity accessing or using this SDK, or any component thereof. "End User License Agreement" means an end user license agreement that provides a (a) limited, nonexclusive right to use the subject Developer Program with no further right to reproduce (except for archival and/or backup copies permitted by law) and/or distribute the subject Developer Program, (b) prohibition against distributing, selling, sublicensing, renting, loaning or leasing the subject Developer Program, (c) prohibition against reverse engineering, decompiling, disassembling or otherwise attempting to discover the source code of the subject Developer Program that is substantially similar to that set forth in Section 3 below, (d) statement that You and your suppliers retain all right, title and interest in the subject Developer Program that is substantially similar to that set forth as Section 5 below, (e) statement that Your suppliers disclaim all warranties, conditions, representations or terms with respect to the subject Developer Program substantially similar to the disclaimer set forth as Section 7 below, and (f) limit of liability substantially similar to that set forth as Section 8 below for the benefit of Your suppliers. ### 2. License Subject to the terms and conditions of this License Agreement, Sensory grants You a non-exclusive, nontransferable, royalty-free license to (a) use the SDK for the sole purpose of internally developing Developer Programs, (b) reproduce and modify Sample Code as a component of Developer Programs that add significant and primary functionality to the Sample Code, (c) reproduce Redistributable Code solely as a component of Developer Programs that add significant and primary functionality to the Redistributable Code and (d) distribute Sample Code and/or Redistributable Code in object code form only as a component of Developer Programs that add significant and primary functionality to the Sample Code and/or Redistributable Code provided that (i) You distribute such object code under the terms and conditions of an End User License Agreement, (ii) You include a copyright notice reflecting the copyright ownership of Developer in such Developer Programs, (iii) You shall be solely responsible to Your customers for any update or support obligation or other liability which may arise from such distribution, (iv) You shall not make any statements that Your Developer Product is "certified," or that its performance is guaranteed, by Sensory, and (v) You do not use Sensory's name or trademarks to market Your Developer Product without written permission of Sensory. Any modified or merged portion of the Sample Code, and/or merged portion of the Redistributable Code, IS subject to this License Agreement. Use of Sensory Software and/or any other Sensory application program is subject to the applicable end user license agreement for such application software even if such Sensory Software is supplied to You in connection with this License Agreement. You may make a limited number of copies of the Documentation to be used by Your employees or consultants for internal development purposes and not for general business purposes or for distribution by any means, and such employees or consultants shall be subject to this License Agreement. You may distribute up to five instances of Your Developer Program with Sensory Software to third parties under this agreement. You may distribute more than five instances of Sensory Software with Your Developer Programs only under separate license from Sensory. Sensory is under no obligation to provide any support under this License Agreement, including upgrades or future versions of the SDK, Sensory Software and/or any component thereof, to Developer, end users, or to any other party. Further developer support, software licensing, trademark licensing and trademark usage information is available through www.Sensoryinc.com. ### 3. Restrictions Except for the limited distribution rights as provided in Section 2 above with respect to Sample Code, Redistributable Code, and Developer Programs, You may not distribute, sell, sublicense, rent, loan, or lease the SDK, Sensory Software, and/or any component thereof to any third party. You also agree not to reverse engineer, decompile, disassemble or otherwise attempt to discover the source code of the SDK, Sensory Software and/or any component thereof except to the extent (i) you may be expressly permitted to decompile under applicable law, (ii) it is essential to do so in order to achieve operability of the SDK or Sensory Software with another software program, and (iii) you have first requested Sensory to provide the information necessary to achieve such operability and Sensory has not made such information available. Sensory has the right to impose reasonable conditions and to request a reasonable fee before providing such information. Any information supplied by Sensory or obtained by you, as permitted hereunder, may only be used by you for the purpose described herein and may not be disclosed to any third party or used to create any software which is substantially similar to the expression of the SDK and/or Sensory Software. ### 4. Confidential Information You agree not to disseminate or in any way disclose Header File Information to any person, firm or business except for Your employees who need to know such Header File Information and who have previously agreed to be bound by a confidentiality obligation consistent with the obligation set forth in this Section 4. Further, You agree to treat the Header File Information with the same degree of care as You accord to Your own confidential information, but in any event no less than reasonable care. Your obligations under this section with respect to the Header File Information shall terminate when You can document that such Header File Information was (i) in the public domain at or subsequent to the time it was communicated to You by Sensory through no fault of yours, (ii) developed by Your employees or agents independently of and without reference to any information communicated to You by Sensory; or (iii) disclosed in response to a valid order by a court or other governmental body, as otherwise required by law, or as necessary to establish the rights of either party under this License Agreement. ### 5. Proprietary Rights You agree to protect Sensory's copyright and other ownership interests in all items in this SDK. You agree that all copies of items in this SDK reproduced for any reason by You will contain the same copyright, trademark, and other proprietary notices as appropriate and appear on or in the master items delivered by Sensory in this SDK. Sensory and/or its suppliers retain all right, title and ownership throughout the world in the intellectual property embodied within the SDK. Except as stated herein, this License Agreement does not grant You any rights to patents, copyrights, trade secrets, trademarks, or any other rights in respect to the items in this SDK. ### 6. Term This License Agreement is effective until terminated. Sensory has the right to terminate Your License immediately if You fail to comply with any term of this License Agreement. Upon any such termination, You must (a) return all full and partial copies of the items in this SDK immediately to Sensory and (b) discontinue distribution of any Sample Code and/or Redistributable Code. Sections 1, 3, 4, 5, 6, 7, 8, 9, 11 and 12 shall survive any termination and/or expiration of this License Agreement. ### 7. Disclaimer of Warranty Sensory licenses the SDK to You on an "AS IS" basis and without warranty of any kind. SENSORY AND ITS SUPPLIERS DO NOT AND CANNOT WARRANT THE PERFORMANCE OR RESULTS YOU MAY OBTAIN BY USING THE SDK. EXCEPT FOR ANY WARRANTY, CONDITION, REPRESENTATION OR TERM TO THE EXTENT TO WHICH THE SAME CANNOT OR MAY NOT BE EXCLUDED OR LIMITED BY LAW APPLICABLE TO YOU IN YOUR JURISDICTION, SENSORY AND ITS SUPPLIERS MAKE NO WARRANTIES, CONDITIONS, REPRESENTATIONS OR TERMS, EXPRESS OR IMPLIED, WHETHER BY STATUTE, COMMON LAW, CUSTOM, USAGE OR OTHERWISE AS TO THE SDK OR ANY COMPONENT THEREOF, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT OF THIRD PARTY RIGHTS, INTEGRATION, MERCHANTABILITY, SATISFACTORY QUALITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Some states or provinces do not allow the exclusion of implied warranties so the above limitations may not apply to You. You may have rights that vary from jurisdiction to jurisdiction. For further warranty information, You may contact the Sensory at the address provided above. ### 8. Limitation of Liability IN NO EVENT WILL SENSORY OR ITS SUPPLIERS BE LIABLE TO YOU FOR ANY DAMAGES, CLAIMS OR COSTS WHATSOEVER ARISING FROM THIS LICENSE AGREEMENT AND/OR YOUR USE OF THE SDK OR ANY COMPONENT THEREOF, INCLUDING WITHOUT LIMITATION ANY CONSEQUENTIAL, INDIRECT, INCIDENTAL DAMAGES, OR ANY LOST PROFITS OR LOST SAVINGS, EVEN IF AN SENSORY REPRESENTATIVE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, DAMAGES, CLAIMS OR COSTS OR FOR ANY CLAIM BY ANY THIRD PARTY. THE FOREGOING LIMITATIONS AND EXCLUSIONS APPLY TO THE EXTENT PERMITTED BY APPLICABLE LAW IN YOUR JURISDICTION. SENSORY'S AGGREGATE LIABILITY AND THAT OF ITS SUPPLIERS UNDER OR IN CONNECTION WITH THIS LICENSE AGREEMENT SHALL BE LIMITED TO FIFTY U.S. DOLLARS ($50.00). Nothing contained in this License Agreement limits Sensory's liability to You in the event of death or personal injury resulting from Sensory's negligence or for the tort of deceit (fraud). Sensory is acting on behalf of its suppliers for the purpose of disclaiming, excluding and/or limiting obligations, warranties and liability as provided in this License Agreement, but in no other respects and for no other purpose. ### 9. Indemnification You agree to defend, indemnify, and hold Sensory and its suppliers harmless from and against any claims or lawsuits, including attorneys' reasonable fees, that arise or result from the use or distribution of Developer Programs, provided that Sensory gives You prompt written notice of any such claim, tenders to You the defense or settlement of such a claim at Your expense, and cooperates with You, at Your expense, in defending or settling such claim. ### 10. Government Regulations You agree that any Developer Program that includes Sample Code and/or Redistributable Code (i) will include in its license agreement a reference to applicable U.S. Government regulations which control licensing of software and (ii) will not be shipped, transferred, or exported into any country or used in any manner prohibited by the United States Export Administration Act or any other export laws, restrictions or regulations (collectively the "Export Laws"). In addition, if any part of the SDK is identified as export controlled items under the Export Laws, you represent and warrant that you are not a citizen, or otherwise located within, an embargoed nation (including without limitation Iran, Iraq, Syria, Sudan, Libya, Cuba, North Korea and Serbia) and that you are not otherwise prohibited under the Export Laws from receiving the SDK. All rights to use the SDK are granted on condition that such rights are forfeited if you fail to comply with the terms of this License Agreement. ### 11. Governing Law This License Agreement will be governed by and construed in accordance with the substantive laws in force in the State of California. The courts of Santa Clara County, California shall each have exclusive jurisdiction over all disputes relating to this License Agreement. This License Agreement will not be governed by the conflict of law rules of any jurisdiction or the United Nations Convention on Contracts for the International Sale of Goods, the application of which is expressly excluded. ### 12. General You may not assign Your rights or obligations granted under this License Agreement without the prior written consent of Sensory. None of the provisions of this License Agreement shall be deemed to have been waived by any act or acquiescence on the part of Sensory, its agents, or employees, but only by an instrument in writing signed by an authorized signatory of Sensory. It is expressly agreed that a breach of Section 3 or 4 of this License Agreement will cause irreparable harm to Sensory and that a remedy at law will be inadequate. Therefore, in addition to any and all remedies available at law, Sensory will be entitled to seek an injunction or other equitable remedies in all legal proceedings in the event of any threatened or actual violation thereof. When conflicting language exists between this License Agreement and any other agreement included in this SDK (except for the Integration Key License Agreement or any agreement supplied with Sensory Software), this License Agreement shall supersede. If either Sensory or Developer employs attorneys to enforce any rights arising out of or relating to this License Agreement, the prevailing party shall be entitled to recover reasonable attorneys' fees. You acknowledge that You have read this License Agreement, understand it, and that it is the complete and exclusive statement of Your agreement with Sensory which supersedes any prior agreement, oral or written, between Sensory and You with respect to the licensing to You of this SDK. No variation of the terms of this License Agreement will be enforceable against Sensory unless Sensory gives its express consent in a writing signed by an authorized signatory of Sensory. Sensory, TrulyHandsfree, TrulyNatural, and the Sensory logo, are either trademarks or registered trademarks of Sensory, Inc. in the United States and/or other countries. *[ROM]: Read-Only Memory, typically nonvolatile flash memory *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "licenses/oss.md" canonical_url: "https://doc.sensory.com/tnl/7.8/licenses/oss/" --- # Open Source licenses One or more of the libraries included in this TrulyNatural SDK uses third-party Open Source components with [permissive license agreements][oss-permissive]. See the _README\*.md_ files in _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/lib//_ for library-specific details. [oss-permissive]: https://en.wikipedia.org/wiki/Permissive_software_license You can omit all Open Source Software from a TrulyNatural binary by: - Compiling with `-DSNSR_OMIT_OSS_COMPONENTS` - or by using custom initialization with models that do not require these components. See [model:ids](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#modelids), [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit), and [reduce code size](https://doc.sensory.com/tnl/7.8/faq.md#reduce-code-size). Query [oss-components](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#oss-components) to determine which of these modules are linked into an application. ### Details: [CRF++](https://github.com/taku910/crfpp/blob/master/BSD) ### Details: [fastText](https://github.com/facebookresearch/fastText/blob/v0.9.2/LICENSE) ### Details: [WebRTC](https://webrtc.googlesource.com/src/+/refs/heads/main/LICENSE) ### Details: [ONNX Runtime](https://github.com/microsoft/onnxruntime/blob/v1.21.1/LICENSE) ### Details: [ONNX Runtime dependencies](https://github.com/microsoft/onnxruntime/blob/v1.21.1/ThirdPartyNotices.txt) [oss-permissive]: https://en.wikipedia.org/wiki/Permissive_software_license "Grants use rights, forbids almost nothing" *[API]: Application Programming Interface *[OSS]: Open-source software *[SDK]: Software Development Kit *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology --- source_path: "models/downloads.md" canonical_url: "https://doc.sensory.com/tnl/7.8/models/downloads/" --- # Downloads _(stt)_ The following STT models are available for download. These are compatible with TrulyNatural STT SDK [7.7.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.7.0) and later. Contact your account representative or [Sensory sales](https://doc.sensory.com/tnl/7.8/contact.md#contact) for additional languages and customizations. **Filename key:** `opt-vg-vad-stt-` - These are pipelines made from the [tpl-opt-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-opt-spot-vad-lvcsr) template with a US English "Voice Genie" wake word in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0) and an STT recognizer in slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1). `-B` - Model includes an NLU component that identifies intents and entities. `-pnc` - Model includes punctuation and capitalization. `-slm` - Model includes a small generative language model. Larger models are more accurate but also require more CPU cycles. | Language { data-sort-default } | Domain | Size in MiB { data-sort-method="number" } | Model | |:---------------------------------|:-----------|--------------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------| | English (US) | automotive | 226 | [opt-vg-vad-stt-enUS-automotive-large-1.3.14-B-pnc_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-enUS-automotive-large-1.3.14-B-pnc_66.snsr) | | English (US) | automotive | 91 | [opt-vg-vad-stt-enUS-automotive-medium-2.3.14-B-pnc_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-enUS-automotive-medium-2.3.14-B-pnc_66.snsr) | | English (US) | automotive | 49 | [opt-vg-vad-stt-enUS-automotive-small-2.3.14-B-pnc_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-enUS-automotive-small-2.3.14-B-pnc_66.snsr) | | English (US) | general | 11 | [opt-vg-vad-stt-enUS-general-micro-2.0.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-enUS-general-micro-2.0.3_66.snsr) | | English (US) | general | 7 | [opt-vg-vad-stt-enUS-general-nano-2.0.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-enUS-general-nano-2.0.3_66.snsr) | | English (US) | general | 199 | [opt-vg-vad-stt-enUS-general-large-2.0.3-pnc_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-enUS-general-large-2.0.3-pnc_66.snsr) | | English (US) | general | 67 | [opt-vg-vad-stt-enUS-general-medium-2.4.3-pnc_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-enUS-general-medium-2.4.3-pnc_66.snsr) | | English (US) | general | 28 | [opt-vg-vad-stt-enUS-general-small-2.2.3-pnc_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-enUS-general-small-2.2.3-pnc_66.snsr) | | English (British) | general | 196 | [opt-vg-vad-stt-enGB-general-large-2.0.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-enGB-general-large-2.0.3_66.snsr) | | English (British) | general | 64 | [opt-vg-vad-stt-enGB-general-medium-2.0.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-enGB-general-medium-2.0.3_66.snsr) | | English (British) | general | 25 | [opt-vg-vad-stt-enGB-general-small-2.0.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-enGB-general-small-2.0.3_66.snsr) | | German | general | 199 | [opt-vg-vad-stt-deDE-general-large-2.2.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-deDE-general-large-2.2.3_66.snsr) | | German | general | 64 | [opt-vg-vad-stt-deDE-general-medium-2.3.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-deDE-general-medium-2.3.3_66.snsr) | | German | general | 25 | [opt-vg-vad-stt-deDE-general-small-2.3.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-deDE-general-small-2.3.3_66.snsr) | | French | general | 202 | [opt-vg-vad-stt-frFR-general-large-2.0.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-frFR-general-large-2.0.3_66.snsr) | | French | general | 64 | [opt-vg-vad-stt-frFR-general-medium-2.3.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-frFR-general-medium-2.3.3_66.snsr) | | French | general | 25 | [opt-vg-vad-stt-frFR-general-small-2.3.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-frFR-general-small-2.3.3_66.snsr) | | Italian | general | 197 | [opt-vg-vad-stt-itIT-general-large-1.2.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-itIT-general-large-1.2.3_66.snsr) | | Italian | general | 64 | [opt-vg-vad-stt-itIT-general-medium-2.3.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-itIT-general-medium-2.3.3_66.snsr) | | Italian | general | 25 | [opt-vg-vad-stt-itIT-general-small-2.3.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-itIT-general-small-2.3.3_66.snsr) | | Japanese | general | 215 | [opt-vg-vad-stt-jaJP-general-large-2.3.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-jaJP-general-large-2.3.3_66.snsr) | | Japanese | general | 64 | [opt-vg-vad-stt-jaJP-general-medium-2.2.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-jaJP-general-medium-2.2.3_66.snsr) | | Japanese | general | 26 | [opt-vg-vad-stt-jaJP-general-small-2.4.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-jaJP-general-small-2.4.3_66.snsr) | | Korean | general | 215 | [opt-vg-vad-stt-koKR-general-large-2.3.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-koKR-general-large-2.3.3_66.snsr) | | Korean | general | 64 | [opt-vg-vad-stt-koKR-general-medium-2.4.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-koKR-general-medium-2.4.3_66.snsr) | | Korean | general | 25 | [opt-vg-vad-stt-koKR-general-small-2.4.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-koKR-general-small-2.4.3_66.snsr) | | Spanish | general | 197 | [opt-vg-vad-stt-esES-general-large-2.2.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-esES-general-large-2.2.3_66.snsr) | | Spanish | general | 64 | [opt-vg-vad-stt-esES-general-medium-2.4.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-esES-general-medium-2.4.3_66.snsr) | | Spanish | general | 25 | [opt-vg-vad-stt-esES-general-small-2.3.3_66](https://cc2.fluent-speech.com/cloud/v12/opt-vg-vad-stt-esES-general-small-2.3.3_66.snsr) | **Provenance:** The wake word, and the speech-to-text acoustic, language, and NLU models are owned by Sensory and have no third-party dependencies. *[API]: Application Programming Interface *[LVCSR]: Large Vocabulary Continuous Speech Recognition model, feed-forward neural net acoustic model with FST decoder *[NLU]: Natural Language Understanding model *[PNC]: Punctuation and Capitalization, an STT model variant that emits cased text with punctuation *[SDK]: Software Development Kit *[SLM]: Generative Small Language Model *[STT]: Speech To Text: transformers with language model and CTC decoding *[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology *[VAD]: Voice Activity Detector --- source_path: "models/index.md" canonical_url: "https://doc.sensory.com/tnl/7.8/models/" --- # Models This distribution includes sample models in _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/model/_ You can also [download models](https://doc.sensory.com/tnl/7.8/models/downloads.md#models-downloads) for additional languages in a range of sizes. Console examples in this section assume _$HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9_ as the SDK install directory; replace that prefix if you installed elsewhere. ## Wake words See the [wake word model type](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) for description of model behavior and settings. ### spot-voicegenie-enUS-6.5.1-m.snsr Fixed-phrase "Voice Genie" wake word for US English. ### spot-hbg-enUS-1.4.0-m.snsr Fixed-phrase "Hello Blue Genie" wake word for US English. ### spot-music-enUS-1.2.0-m.snsr Music command set for US English. Commands include "play music", "pause music", "stop music", "previous song", and "next song". ## Adapting wake word See the [adapting wake word model type](https://doc.sensory.com/tnl/7.8/models/types/ca.md#ca-type) for a description of model behavior and settings. ### ca-voicegenie-enUS-1.1.0.snsr This is a fixed-phrase spotter for "Voice Genie" in US English that adapts to users' speech to improve false-accept rates. Model adaptation and enrollment happens automatically and without any additional code requirements — you can use this model as a drop-in replacement for the fixed-phrase [Voice Genie](https://doc.sensory.com/tnl/7.8/models/index.md#spot-voicegenie-enUS) spotter. Configuration settings of particular interest include [cache-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#cache-file) and [max-users](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-users). Use [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator), [delete-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#delete-user), and [rename-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#rename-user) to manage user enrollments. **Note:** This model requires support for [multi-threading](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#thread-support). ### Details The reported [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) value changes once enrollment has identified and enrolled a new speaker. ```console % cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9 # two different speakers saying "voice genie" % bin/snsr-eval -t model/ca-voicegenie-enUS-1.1.0.snsr\ -s cache-file=ca-vg-cache.snsr\ -s max-users=3 2235 3045 voice_genie 6810 7545 voice_genie 11745 12525 user1/voice_genie 16845 17595 user1/voice_genie 29355 30180 voice_genie 34845 35820 user2/voice_genie 37815 38520 user1/voice_genie 40080 40905 user2/voice_genie ^C # restart, loading enrollments from the cache file % bin/snsr-eval -t model/ca-voicegenie-enUS-1.1.0.snsr\ -s cache-file=ca-vg-cache.snsr\ -s max-users=3 12045 13035 user2/voice_genie 15180 15840 user1/voice_genie 17745 18465 user1/voice_genie 20175 20820 user2/voice_genie ^C ``` ## Wake word enrollment See the [wake word enrollment model type](https://doc.sensory.com/tnl/7.8/models/types/enroll.md#enroll-type) for a description of model behavior and settings. ### eft-hbg-enUS-23.0.0.9.snsr EFT spotter for "Hello Blue Genie", US English. This model produces wake words with a low imposter accept rate. ### udt-universal-3.67.1.0.snsr UDT enrollment. This model creates spotters with nine different operating points and supports multiple languages. Optimized for German, English (Australian, British, Indian, United States), Spanish (European Union, North American), French (European Union), Italian, Korean, Brazilian Portuguese, and Mandarin Chinese. ### udt-enUS-5.1.1.9.snsr UDT enrollment with backwards compatibility. **Note:** This older model produces enrolled wake words with reduced accuracy. Use this model only when targeting a THF Micro 3.x DSP port, or when the wake word is followed by additional validation. ## VAD See the [VAD model type](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type) for a description of model behavior and settings. ### vad-ml-3.0.0.snsr Deep-learned stand-alone Voice Activity Detector. ## LVCSR _(tnl)_ See the [LVCSR model type](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type) for a description of model behavior and settings. ### lvcsr-build-enUS-12.13.1-5MB.snsr _(tnl)_ US English recognizer with 4.9 MiB acoustic model and support for [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition). Supports classes and NLU. Use [search.frame-nota](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#searchframe-nota) to adjust out-of-grammar rejection. **Example:** ``` % cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9 % snsr-eval -t model/lvcsr-build-enUS-12.13.1-5MB.snsr\ -s partial-result-interval=0 \ -f grammar-stream data/grammars/enrollments-nlu-slot.txt \ data/enrollments/armadillo-1-2-c.wav NLU intent: navigate (0) = how far away is winco NLU entity: place (0) = winco 285 2100 armadillo how far away is winco ``` ### lvcsr-lib-enUS-1.2.0.snsr _(tnl)_ US English class library. This provides pre-compiled classes for common domains. Use [lvcsr-build-enUS](https://doc.sensory.com/tnl/7.8/models/index.md#lvcsr-build-enUS) to simplify [grammar-based recognition](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) grammars. See [class libraries](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-class-libraries) for a usage example. _lvcsr-lib-enUS-1.2.0.json_ provides the content of the class description table below in machine-readable format. ### Details: lvcsr-lib-enUS-1.2.0.snsr class library **s.alarm-phrases** Basic commands for alarm. - language: enUS - version: 0.0.1 - description: Basic commands for alarm. - detail: Phrases for setting an alarm, including specific times (see s.time). - examples: wake me up at