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
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 , set alarm for tomorrow, create an alarm for , cancel alarm for , dismiss my alarm for tomorrow, end alarm, stop alarm, dismiss alarm, cancel alarm, snooze alarm, snooze for minutes, cancel all alarms, set alarm for every week day, set my alarm for every
- category: command sets
**s.alphanumeric**
Matches an individual letter (a-z) or an individual integer (0-9).
- language: enUS
- version: 0.0.2
- description: Matches an individual letter (a-z) or an individual integer (0-9).
- detail: Individual alphabet letters including enUK 'zed' and adjectives used for spelling, plus individual numbers zero through nine, including 'oh'.
- examples: zero, oh, , , zed, cap , capital , big , lowercase , uppercase , little , double
- category: characters
**s.call-emergency**
Common ways of calling for help in case of emergency.
- language: enUS
- version: 0.0.1
- description: Common ways of calling for help in case of emergency.
- detail: Ways to call emergency services; does not include "help" or "help me". Use this grammar with caution.
- examples: , it's an emergency, it is an emergency, this is an emergency, i'm having an emergency, we're having an emergency
- category: emergency
**s.clock-phrases**
Basic commands for setting a clock.
- language: enUS
- version: 0.0.1
- description: Basic commands for setting a clock.
- detail: Phrases for setting a clock, including specific times (see s.time).
- examples: time, what time is it, what is the time, what's the time, set time to , change time to , set clock to , change clock to
- category: command sets
**s.color.extended**
Matches individual color names.
- language: enUS
- version: 0.0.1
- description: Matches individual color names.
- detail: Assortment of less common colors.
- examples: indigo, teal, beige, olive, bronze, camel, citron, copper, coral, cyan, chestnut, blond, ebony, gold, jade, lavender, mint, denim, garnet, gunmetal, linen, eggshell, eggplant, puce, taupe, silver, vermillion, navy, magenta, mustard, saffron, sage, maroon, tangerine, turquoise, rose, oxblood, violet
- category: color
**s.color**
Matches individual color names.
- language: enUS
- version: 0.0.4
- description: Matches individual color names.
- detail: Primary and secondary colors.
- examples: black, blue, brown, gray, green, orange, pink, purple, red, white, yellow
- category: color
**s.control.car**
Simple command set for car voice control.
- language: enUS
- version: 0.0.1
- description: Simple command set for car voice control.
- detail: Basic commands for car voice control, including door controls, window controls, environment controls, basic stereo control, mirror/wiper/lights control.
- examples: open driver's side window, close the passenger's side window, roll down front windows, roll up all the windows, lock passenger's side door, child lock back doors, unlock front doors, turn off front defroster, turn on heat, turn up heater, turn down the A C, turn fan up, turn on windshield wipers, open garage, close garage door, turn on navigation, end navigation, turn on radio, turn the front speakers up, turn down the rear speakers, turn up treble, turn the bass down, increase back wiper speed, decrease wiper speed, unfold side mirrors, fold right side mirror, turn on driver's side seat warmer, turn the passenger's side seat warmer down, turn on the dome light
- category: command sets
**s.control.door**
Basic commands for smart lock/door control.
- language: enUS
- version: 0.0.1
- description: Basic commands for smart lock/door control.
- detail: Simple command set for controlling a smart lock/door.
- examples: lock the door, unlock my door, open door, close the door, is the door open, is my door open
- category: command sets
**s.control.environment**
General, basic commands for environment control.
- language: enUS
- version: 0.0.1
- description: General, basic commands for environment control.
- detail: Commands for environment control devices, such as fans, AC, space heaters.
- examples: turn on, turn off, turn up, turn down, start, stop, set speed to, change speed to, set speed to , change speed to , set to percent, change to percent, set to , change to
- category: command sets
**s.control.lights**
Simple command set for voice-controlled lights.
- language: enUS
- version: 0.0.1
- description: Simple command set for voice-controlled lights.
- detail: Basic commands for voice-controlled lights.
- examples: turn on all the hallway lights, turn off closet light, dim the den lights, brighten all the master bath lights, set foyer light to off, turn all the breakfast nook lights on
- category: command sets
**s.control.media**
Basic media control phrases.
- language: enUS
- version: 0.0.1
- description: Basic media control phrases.
- detail: Basic, common controls for music, movies, etc.
- examples: play, pause, stop, skip, skip to, next, fast forward, back, rewind, fast rewind, reverse, repeat, start, shuffle
- category: command sets
**s.control.media.tv**
Simple command set for voice-controlled television.
- language: enUS
- version: 0.0.1
- description: Simple command set for voice-controlled television.
- detail: Basic commands for voice-controlled television, see s.switch for specific subcommands for "".
- examples: cable, music, browser, apps, streaming, channel , recordings, guide, input , turn on the t v, switch off my television, t v off, television on, switch t v off, turn television on, power on, power off, turn volume to , adjust volume down , turn volume up, mute t v, unmute the television, turn on closed captioning, next channel, channel up, channel down
- category: command sets
**s.control.media.volume**
Simple commands for audio volume control.
- language: enUS
- version: 0.0.1
- description: Simple commands for audio volume control.
- detail: Typical, general commands for controlling audio volume, for home/car smart speaker, television, etc.
- examples: increase the , decrease the , turn up the , turn down the , turn the up, turn to five, turn up to ten, turn down to one, mute , louder, softer, quieter, up, down
- category: command sets
**s.control.phone**
Basic commands for calling/messaging control.
- language: enUS
- version: 0.0.2
- description: Basic commands for calling/messaging control.
- detail: Typical, open-ended calling/messaging commands for voice-control assistant on phone. All can be followed by a specific entity/contact name.
- examples: send text, send a text to, send voice message, send audio message to, reply to, text to, show message, play message from, show emails, show me emails from, read my recent messages, show my new messages from, play all voice messages, play all voicemail, play new voicemail messages from, send email, send an email to, show contacts, call
- category: command sets
**s.control.thermostat**
Basic commands for thermostat.
- language: enUS
- version: 0.0.1
- description: Basic commands for thermostat.
- detail: Phrases for setting an thermostat, including specific temperatures in C or F (see s.temperature.thermostat.celsius and s.thermostat.fahrenheit).
- examples: set thermostat to , turn thermostat up degrees, turn thermostat down degrees, make it much warmer, make it much cooler, make it degrees warmer, make it degrees cooler, what is the temperature
- category: command sets
**s.control.vacuum**
Basic commands for vacuum cleaner.
- language: enUS
- version: 0.0.1
- description: Basic commands for vacuum cleaner.
- detail: Phrases for a voice-controlled vacuum cleaner, including room names to direct vacuum (see s.rooms).
- examples: start vacuuming, stop vacuuming, resume vacuuming, end vacuuming, pause vacuuming, unpause vacuuming, start vacuum, stop vacuum, pause vacuum, unpause vacuum, dock vacuum, charge vacuum, where is the vacuum, is the vacuum charging, is the vacuum charged, is vacuum docked, vacuum the , start vacuuming the , resume vacuuming the , end vacuuming the
- category: command sets
**s.control.virtual-meeting**
Basic commands for controlling a virtual meeting platform.
- language: enUS
- version: 0.0.1
- description: Basic commands for controlling a virtual meeting platform.
- detail: Assortment of basic commands for interacting with and controlling a virtual meeting platform.
- examples: mute, mute self, mute all, unmute, unmute self, unmute all, initiate new meeting, new meeting, schedule meeting, go to upcoming meetings, past meetings, go to recordings, go to chat, help, test audio, test video, switch microphone, switch video, leave meeting, blur background
- category: command sets
**s.date**
Common ways of saying individual dates.
- language: enUS
- version: 0.0.1
- description: Common ways of saying individual dates.
- detail: Covers dates from January 1, 1800 to December 31, 2099; with and without years.
- examples: first of january, the second of february, the third of march two thousand fifteen, the fourth of april two thousand and fifteen, may fifth, june the sixth, july seventh nineteen eighty, august the eighth twenty oh two
- category: date
**s.duration-queries**
General queries about how long something is, to be followed by nouns.
- language: enUS
- version: 0.0.1
- description: General queries about how long something is, to be followed by nouns.
- detail: An assortment of open-ended queries involving multiple interrogatives which can be combined with entities for a variety of duration applications. (Does not include phrases specific to setting a timer; see s.timer-phrases.grm for this application.)
- examples: how long is, for how long is, what's the duration of, what is the length of time of, please show me how long is, tell me the duration of, I want to know what the length of time is of
- category: commands
**s.email**
Common ways of spelling out individual email addresses.
- language: enUS
- version: 0.0.1
- description: Common ways of spelling out individual email addresses.
- detail: Produces a spelled-out email address, with common domains or custom, spelled-out domain.
- examples: a b c at gmail dot com, h e l l o one two three at yahoo dot com, m y dot e m a i l underscore a d d r e s s at outlook dot com, one dash two dash three at i cloud dot com, a plus b plus c at aol dot com, x y z at hotmail dot com, i j k at ms dot com, e m a i l at m y d o m a i n dot org, e m a i l at y o u r dash d o m a i n dot com
- category: email
**s.help**
Device assistance commands.
- language: enUS
- version: 0.0.2
- description: Device assistance commands.
- detail: Common ways to ask for help with a device.
- examples: help, help me, help menu, what do i say, what can i do, how can i use this, how do i use this thing
- category: help
**s.increase-decrease**
Increase/decrease commands.
- language: enUS
- version: 0.0.2
- description: Increase/decrease commands.
- detail: Generic increase and decrease language. No "bump it", "make it quieter/hotter", etc.
- examples: turn up, turn it down, decrease, increase, crank it, crank up
- category: commands
**s.integer-billions**
Matches individual long forms of integers from 1 billion to 999 billion.
- language: enUS
- version: 0.0.1
- description: Matches individual long forms of integers from 1 billion to 999 billion.
- detail: Does not include common rounded/float versions (ie. 1.5 billion), or 'a billion' (for easier integration in a larger number set).
- examples: one billion, twelve billion five million and three hundred, ninety billion and ninety nine million nine thousand and one, one hundred eighty billion twenty one million, three hundred twenty one billion and eighty two million and two, nine hundred ninety nine billion nine hundred ninety nine million nine hundred ninety nine thousand nine hundred and ninety nine
- category: numbers
**s.integer-millions**
Matches individual long forms of integers from 1 million to 999 million.
- language: enUS
- version: 0.0.1
- description: Matches individual long forms of integers from 1 million to 999 million.
- detail: Does not include common rounded/float versions (ie. 1.5 million), or 'a million' (for easier integration in a larger number set).
- examples: one million, one million one hundred thousand, one million one hundred thousand and one, two million and sixteen, three hundred million three thousand and two, nine hundred ninty nine million nine hundred ninety nine thousand nine hundred and ninety nine
- category: numbers
**s.integer-thousands**
Matches individual numbers from one thousand to 999 thousand.
- language: enUS
- version: 0.0.1
- description: Matches individual numbers from one thousand to 999 thousand.
- detail: Does not include 'a thousand', etc, for easier integration in a larger number set.
- examples: one thousand, two thousand and one, two thousand eight hundred and ninety nine, nine hundred ninety nine thousand nine hundred and ninety nine
- category: numbers
**s.letter**
Matches an individual letter (a-z).
- language: enUS
- version: 0.0.2
- description: Matches an individual letter (a-z).
- detail: Individual alphabet letters, including enUK "zed", plus optional adjectives used for spelling.
- examples: , cap , capital , big , lowercase , uppercase , little , double
- category: characters
**s.location-queries**
General queries to be followed by place names.
- language: enUS
- version: 0.0.1
- description: General queries to be followed by place names.
- detail: An assortment of open-ended queries involving multiple interrogatives which can be combined with entities for location-app-specific purposes.
- examples: where is, what are the directions to, map my route to, show the way to, I need a map to, tell me how to get to, how do I get to, guide me to, what's the way I could drive to, what is the way I might find, how do you drive to, tell me how to locate, how would I get to, get me to, how might one drive to, could you please help me find, please tell me where one would locate
- category: commands
**s.money**
Matches individual US currency expressions.
- language: enUS
- version: 0.0.1
- description: Matches individual US currency expressions.
- detail: Combinations of cents and dollars up to 100 dollars.
- examples: zero cents, zero dollars, one cent, one dollar, cents, , , and cents, ('two ninety nine'), oh ('three oh five')
- category: money
**s.noun-queries**
General queries about where something is, to be followed by nouns.
- language: enUS
- version: 0.0.1
- description: General queries about where something is, to be followed by nouns.
- detail: An assortment of open-ended queries involving multiple interrogatives which can be combined with entities for a variety of applications. (Does not include location-app-specific queries involving words "drive", "guide", "route", or "map".)
- examples: find, get, locate, show, show me, help me find, help me locate, please locate, where is, what's the way to get, what's the way one might get to, what's the way you can get to, what's the way I could locate, what's the way to see, show me where to find, please show me where one would get, tell me how I find, please tell me how one might get, where would I see, where might one locate, how can one get to, how would I find, how do I see, I want to know how one might get to
- category: commands
**s.number-integer-0-1trillion**
Matches individual cardinal numbers zero through one trillion.
- language: enUS
- version: 0.0.1
- description: Matches individual cardinal numbers zero through one trillion.
- detail: Zero through one trillion, with optional 'and' between trillion, millions, thousand, etc. components.
- examples: zero, one, ninety eight, one hundred ninety eight, six thousand one hundred and ninety eight, five million six thousand six hundred thousand thirty two, one and a half billion, a trillion, one trillion
- category: numbers
**s.number-integer-0-9**
Matches individual cardinal numbers zero through nine.
- language: enUS
- version: 0.0.1
- description: Matches individual cardinal numbers zero through nine.
- detail: Zero through nine.
- examples: zero, one, two, three, four, five, six, seven, eight, nine
- category: numbers
**s.number-integer-0-100**
Matches cardinal numbers zero through one hundred.
- language: enUS
- version: 0.0.1
- description: Matches cardinal numbers zero through one hundred.
- detail: Zero through one hundred, including 'a hundred'.
- examples: zero, one, eleven, thirty, thirty four, ninety nine, one hundred, a hundred
- category: numbers
**s.number-integer-0-999**
Matches individual cardinal numbers zero through nine hundred ninety nine.
- language: enUS
- version: 0.0.2
- description: Matches individual cardinal numbers zero through nine hundred ninety nine.
- detail: Zero through nine hundred ninety nine, with optional 'and' between hundreds and tens component.
- examples: zero, one, eleven, twenty one, one hundred twelve, nine hundred and ninety nine
- category: numbers
**s.number-integer-11-19**
Matches individual cardinal numbers eleven through nineteen.
- language: enUS
- version: 0.0.1
- description: Matches individual cardinal numbers eleven through nineteen.
- detail: Eleven through nineteen.
- examples: eleven, twelve, thirteen, fourteen, fifteen, sixteen, seventeen, eighteen, nineteen
- category: numbers
**s.number-integer-hundred-thousands**
Matches individual cardinal numbers one hundred thousand through nine hundred ninety nine thousand nine hundred ninety nine.
- language: enUS
- version: 0.0.1
- description: Matches individual cardinal numbers one hundred thousand through nine hundred ninety nine thousand nine hundred ninety nine.
- detail: One hundred thousand through nine hundred ninety nine thousand nine hundred ninety nine, with optional 'and' between thousands, hundreds, etc., components.
- examples: one hundred thousand, one hundred and two thousand, four hundred twenty one thousand and three hundred, forty one thousand one hundred and three
- category: numbers
**s.number-ordinal-0-9**
Matches individual ordinal numbers 'zeroth' through 'ninth'.
- language: enUS
- version: 0.0.1
- description: Matches individual ordinal numbers 'zeroth' through 'ninth'.
- detail: Zeroth through ninth.
- examples: zeroth, first, second, third, fourth, fifth, sixth, seventh, eighth, ninth
- category: numbers
**s.number-ordinal-10_99**
Matches individual cardinal numbers 'tenth' through 'ninety ninth'.
- language: enUS
- version: 0.0.1
- description: Matches individual cardinal numbers 'tenth' through 'ninety ninth'.
- detail: Tenth through ninety ninth.
- examples: tenth, eleventh, twenty first, thirtieth, eighty ninth
- category: numbers
**s.on-off**
On and off commands.
- language: enUS
- version: 0.0.1
- description: On and off commands.
- detail: Common expressions for turning devices on and off.
- examples: turn off, turn on, switch off, switch on, turn off, turn on, start, stop
- category: on-off
**s.ordering**
General, open-ended phrases for ordering/requesting.
- language: enUS
- version: 0.0.1
- description: General, open-ended phrases for ordering/requesting.
- detail: An assortment of open-ended phrases for ordering which can be combined with specific entities for a variety of applications.
- examples: may I have, may I please get, may I try a, may I order one, can I try, can I please order, can I grab two, can I please have three, could I get, could I please have several, could I try that, could I please order this, I'll take, I'll take the, I'd like to have, I'd like to have several, I want, I want three, give me, give me one, please give me, please give me the
- category: commands
**s.percent**
Matches individual percentages using cardinal numbers.
- language: enUS
- version: 0.0.2
- description: Matches individual percentages using cardinal numbers.
- detail: Percents zero to one hundred (with 'percent' unit).
- examples: percent, one hundred percent, a hundred percent
- category: percent
**s.phone-number**
Matches individual phone numbers.
- language: enUS
- version: 0.0.1
- description: Matches individual phone numbers.
- detail: Common ways to say 10 digit phone numbers in the US; includes options for 'one' and 'nine' international dialing code, eight-hundred. Limits area codes to 200-900 (US). Interchangeable 'zero' and 'oh'.
- examples: one two three four five six seven eight nine oh, four one oh three three oh nine two nine two, one three zero nine three five five two zero two one
- category: phone-number
**s.rooms**
Matches an individual room name.
- language: enUS
- version: 0.0.2
- description: Matches an individual room name.
- detail: Individual names for types of rooms, for homes and businesses.
- examples: porch, living room, parlor, entry, entry way, entry room, den, breakfast nook, hallway, mud room, kitchen, bathroom, master bath, master bathroom, restroom, bedroom, guest room, play room, dining room, upstairs, downstairs, laundry room, entrance, basement, pantry, family room, foyer, den, sunroom, library, studio, nursery, office, home office, rec room, recreation room, attic, conference room, conference room, meeting room, reception, reception area, server room, break room, wellness room
- category: rooms
**s.single-digit-integer**
Matches individual numbers one through nine.
- language: enUS
- version: 0.0.2
- description: Matches individual numbers one through nine.
- detail: Does not include zero, as it may not apply to all use cases.
- examples: one, two, three, four, five, six, seven, eight, nine
- category: numbers
**s.single-digit-ordinal**
Matches individual ordinal numbers 'first' through 'ninth'.
- language: enUS
- version: 0.0.2
- description: Matches individual ordinal numbers 'first' through 'ninth'.
- detail: First through ninth, does not include 'zeroth'.
- examples: first, second, third, fourth, fifth, sixth, seventh, eighth, ninth
- category: numbers
**s.special-character**
Commonly occuring special characters.
- language: enUS
- version: 0.0.2
- description: Commonly occuring special characters.
- detail: Ways to speak common special characters like punctuation.
- examples: period, comma, stop, at sign, hashtag, pound sign, dollar sign, plus, curly bracket, right curly brace, open angle bracket, open paren, question mark, exclamation mark, apostrophe, pipe, colon, underscore, carat
- category: characters
**s.switch**
Open-ended commands for general navigation.
- language: enUS
- version: 0.0.1
- description: Open-ended commands for general navigation.
- detail: Common commands for switching from one item to another, in a menu, on a television, and more.
- examples: go to, switch to, watch, turn to, change to, put on, tune to
- category: commands
**s.temperature.oven.celsius**
Matches individual temperatures 100 C to 300 C for use with household ovens.
- language: enUS
- version: 0.0.2
- description: Matches individual temperatures 100 C to 300 C for use with household ovens.
- detail: Values from one hundred to three hundred, with optional 'degree' and/or 'celsius' appended.
- examples: , degrees, degrees celsius
- category: temperature
**s.temperature.oven.fahrenheit**
Matches individual temperatures 200 C to 500 F for use with household ovens.
- language: enUS
- version: 0.0.1
- description: Matches individual temperatures 200 C to 500 F for use with household ovens.
- detail: Values from two hundred to five hundred with optional "degrees" and "fahrenheit" appended.
- examples: , degrees, degrees fahrenheit
- category: temperature
**s.temperature.thermostat.celsius**
Matches individual temperatures 10 C to 40 C (thermostat).
- language: enUS
- version: 0.0.1
- description: Matches individual temperatures 10 C to 40 C (thermostat).
- detail: Values from one to forty, with optional "degrees" and "celsius", for use with household thermostats.
- examples: , degrees, degrees celsius
- category: temperature
**s.temperature.thermostat.fahrenheit**
Matches individual temperatures 40 to 100 (thermostat).
- language: enUS
- version: 0.0.2
- description: Matches individual temperatures 40 to 100 (thermostat).
- detail: Values from forty to one hundred, with optional "degrees" and "fahrenheit", for use with household thermostats.
- examples: , degrees, fahrenheit, degrees fahrenheit
- category: temperature
**s.time**
Colloquial time/clock phrases in US English (no 'military' time).
- language: enUS
- version: 0.0.1
- description: Colloquial time/clock phrases in US English (no 'military' time).
- detail: 1 through 12 pm and am, half past/quarter till/ten to etc., o'clock, noon/midnight, afternoon/morning/evening/night matched to their common equivalent numeric hours (with some overlap in evening, night, and afternoon).
- examples: five thirteen, seven thirty a m, eight o'clock p m, twenty till eight, five past noon, ten to midnight, a quarter after four, quarter before nine, six thirteen in the morning, eight o'clock in the evening, a quarter past ten o'clock
- category: time
**s.timer-phrases**
Basic commands for setting a timer.
- language: enUS
- version: 0.0.1
- description: Basic commands for setting a timer.
- detail: Phrases for setting a timer, including specific durations (details in s.timer).
- examples: the timer, set a timer for , please start the timer for , start a timer, set timer, timer, how much time is left on my timer, wake me in
- category: command sets
**s.timer**
Durations for setting timers and alarms.
- language: enUS
- version: 0.0.1
- description: Durations for setting timers and alarms.
- detail: Seconds, minutes, hours and combinations for setting timers and alarms.
- examples: a sec, a second, one second, a minute, one minute, half hour, a half hour, one half hour, an hour, one hour, one hour and a half, an hour and a half, seconds, minutes, hours, minutes seconds, minutes and seconds, hours minutes, hours and minutes
- category: timer
**s.two-digit-integer**
Matches individual two-digit cardinal numbers, 10-99.
- language: enUS
- version: 0.0.2
- description: Matches individual two-digit cardinal numbers, 10-99.
- detail: Ten through ninety nine.
- examples: ten, eleven, eighteen, forty six, seventy, ninety nine
- category: numbers
**s.two-digit-ordinal**
Matches individual two-digit ordinal numbers, 10-99.
- language: enUS
- version: 0.0.2
- description: Matches individual two-digit ordinal numbers, 10-99.
- detail: Tenth through ninety ninth.
- examples: tenth, eleventh, twenty third, eightieth, ninety ninth
- category: numbers
**s.verb-queries**
General queries about how something is done, to be followed by verbs.
- language: enUS
- version: 0.0.1
- description: General queries about how something is done, to be followed by verbs.
- detail: An assortment of open-ended queries involving multiple interrogatives which can be combined with actions for a variety of applications.
- examples: how do I, show me how I, tell me how you, please show me how I can, tell me how I might, please show me how you, please help me to, how to, I want to know how I, how might I, help me, how can I, how to, I want to know how you, I want to know how you can, please tell me how you might
- category: commands
**s.weight**
Matches individual weights, in pounds and ounces.
- language: enUS
- version: 0.0.2
- description: Matches individual weights, in pounds and ounces.
- detail: Combinations of pounds and ounces, up to 100 pounds and 100 ounces. Allows for decimal pound amounts.
- examples: one pound, one ounce, pounds, one pound ounces, one pound and ounces, pounds ounces, pounds and ounces, point pounds, one pound one ounce, and a half pounds
- category: weight
**s.when-queries**
General queries about when something is, to be followed by nouns.
- language: enUS
- version: 0.0.1
- description: General queries about when something is, to be followed by nouns.
- detail: An assortment of open-ended queries involving multiple interrogatives which can be combined with entities for a variety of time applications. (Does not include phrases specific to setting a timer; see s.timer-phrases.grm for this application.)
- examples: what time is, at what hour is, what's the time of day of, what is the time of, please show me what hour is, please show when I might get, please show me when one might get, please tell me the hour of, tell me when you are going to, show me when is, I want to know when you can get, I want to know the time of, I want to know when is
- category: commands
**s.yes-no**
Common yes/no responses.
- language: enUS
- version: 0.0.2
- description: Common yes/no responses.
- detail: Common ways of saying yes or no. Does not include things like "nah I'm good", "right", "thanks", and "that's it".
- examples: yep, yup, yeah, yeah sure, sure, yes, yes please, please, okay, nope, no, no thanks, nah, no thank you
- category: yes-no
## STT _(stt)_
See the [STT model type](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type) for a description of
model behavior and settings.
You can [download](https://doc.sensory.com/tnl/7.8/models/downloads.md#models-downloads) additional models for other languages
in a range of different sizes.
### stt-enUS-automotive-medium-2.3.15-pnc.snsr _(stt)_
STT recognizer with broad-domain support and special
focus on automotive command-and-control tasks. It includes a machine-learned
NLU component that identifies automotive intents and entities.
Results include capitalization and punctuation.
This model requires STT support, which currently depends on third-party
Open Source modules that are optionally included in the TrulyNatural SDK
See [Open Source Licenses](https://doc.sensory.com/tnl/7.8/licenses/oss.md#open-source-licenses) for details.
All model components (acoustic, language, and NLU) are owned by Sensory.
### Details: NLU intents and entities
| Intent | Entities | Examples |
|:-------|:---------|:---------|
| activate_car_alarm | | car alarm on set the car alarm |
| activate_lights | automatic_lights, dashboard_lights, daytime_running_lights, door_lights, fog_lights, hazard_lights, high_beams, interior_lights, low_beams, parking_lights, light, front, rear, driver_side, left_side, passenger_side, right_side, duration, percentage_value, trunk | turn on the headlights flash the brights cabin lights on |
| adjust_mirror | front, rear, driver_side, left_side, passenger_side, right_side, side, rearview, direction, adjust_type, percentage_value, length_unit length_unit | adjust driver side mirror fold in the side mirrors lower rearview mirror set the passenger side mirror up one inch |
| affirm | | confirm please |
| answer_call | contact_name | accept my call answer call from ylana |
| average_m_p_g | | check gas mileage |
| battery_level | number_unit number_unit | check the battery level |
| bot_challenge | | am i talking to a human are you a bot |
| call_contact | contact_name, message | call jeff make a call to marco |
| call_emergency | ems | call nine one one call the police |
| call_end | | hang up call |
| call_general | | digit dial make a call |
| call_number | phone_number | call seven six five seven three zero six four one five |
| camera_off | camera, front, rear, rearview, side | back camera off |
| camera_on | camera, front, rear, rearview, side | activate all cameras turn on the dash cam |
| cancel | | cancel quit |
| change_gears | gear | put it in reverse shift into park |
| change_temp_unit | temperature_unit | change to celsius |
| change_time_zone | time_zone | change time zone to mountain standard time |
| check_messages | contact_name | check my messages how many messages in my inbox |
| climate_sync | hvac, left_side, right_side | turn on climate sync turn off synchronization of the a c |
| close_door | front, rear, driver_side, left_side, passenger_side, right_side, fuel_door, garage_door, side_door, van_door | back doors shut close driver's side door lower garage door |
| close_glove_box | glove_box | shut the cubby-hole close the jocky box raise the glove compartment |
| close_hood | hood, rear, trunk rear, hazard_lights | close my bonnet slam the hood |
| close_trunk | trunk | close the tailgate lower the trunk shut the boot |
| close_window | front, rear, driver_side, left_side, passenger_side, right_side, roof, percentage_value, adjust_type, number_unit, length_unit adjust_type, number_unit, length_unit | close the sunroof close the back passenger's side windows all the way front window up |
| connect_bluetooth | | bluetooth connect device car connect cell phone pair headphones |
| current_speed | speed_unit | display speed tell me what the speedometer says |
| d_v_d_player | adjust_type, percentage_value, front, rear | play a d v d for the kids |
| deactivate_car_alarm | | deactivate safety system silence the car alarm |
| deactivate_lights | automatic_lights, dashboard_lights, daytime_running_lights, door_lights, fog_lights, hazard_lights, high_beams, interior_lights, low_beams, parking_lights, light, front, rear, driver_side, left_side, passenger_side, right_side, duration, percentage_value, trunk | all lights off cabin light off deactivate adaptive driving beam |
| decline_call | contact_name | decline call from ylana dismiss incoming call |
| decrease_cruise_control | speed_unit, adjust_type, percentage_value, number_unit | decrease cruise control speed by eighty kilometeres per hour decrease cruise forty lower the speed of the cruise |
| decrease_display | rear, front | dim the screen |
| decrease_fan_speed | front, rear, driver_side, left_side, passenger_side, right_side, hvac, adjust_type, percentage_value, duration, number_unit, safety_lock duration, number_unit, safety_lock | change fan to slower decrease fan some |
| decrease_lights | automatic_lights, dashboard_lights, daytime_running_lights, door_lights, fog_lights, hazard_lights, high_beams, interior_lights, low_beams, parking_lights, light, front, rear, driver_side, left_side, passenger_side, right_side, percentage_value, trunk | dim interior lights turn down the dashboard lights |
| decrease_seat_warmers | front, rear, driver_side, left_side, passenger_side, right_side, adjust_type, percentage_value | decrease my seat warmer make warmers cooler set all of my seat warmers down |
| decrease_steering_wheel_warmer | | |
| decrease_temperature | adjust_type, percentage_value, front, rear, driver_side, passenger_side, hvac, number_unit, temperature_unit | decrease heat decrease temperature by ten degrees celsius it's hot in here |
| decrease_volume | adjust_type, percentage_value, front, rear, number_unit front, rear, number_unit | crank audio level down audio softer |
| decrease_wiper_speed | front, rear, percentage_value, number_unit | decrease back windshield wiper speed lower the front wiper by a little bit |
| deny | | do not send no |
| feature_list | | what can i say what features do you have again |
| fuel_level | | check fuel level do i need to get gas soon how empty is the petrol tank |
| give_duration | duration | five minutes for two minutes |
| give_name | contact_name | jeff megan |
| give_time | time | ten a m three thirty p m |
| good_bye | | see you later |
| greet | | hello |
| honk_horn | | beep the horn honk |
| increase_cruise_control | speed_unit, adjust_type, percentage_value, number_unit | bump up ths speed by three miles per hour increase cruise speed ten |
| increase_display | rear, front | make the screen brighter increase display brightness |
| increase_fan_speed | front, rear, driver_side, left_side, passenger_side, right_side, hvac, adjust_type, percentage_value, duration, number_unit, safety_lock | crank up the fans change fan speed to higher speed |
| increase_lights | automatic_lights, dashboard_lights, daytime_running_lights, door_lights, fog_lights, hazard_lights, high_beams, interior_lights, low_beams, parking_lights, light, front, rear, driver_side, left_side, passenger_side, right_side, percentage_value, trunk, driver_side, right_side | make the dome lights brighter |
| increase_seat_warmers | front, rear, driver_side, left_side, passenger_side, right_side, adjust_type, percentage_value | change seat warmer faster speed increase all my seat warmer |
| increase_steering_wheel_warmer | | |
| increase_temperature | adjust_type, percentage_value, front, rear, driver_side, passenger_side, hvac, number_unit, temperature_unit, temperature_unit | crank up heater i'm extremely cold increase the a c by fifty percent make it warmer |
| increase_volume | adjust_type, percentage_value, front, rear, number_unit, artist | change the volume louder crank up the music level |
| increase_wiper_speed | front, rear, percentage_value, number_unit | all of my wipers higher |
| lock_door | front, rear, driver_side, left_side, passenger_side, right_side, safety_lock, van, fuel, hood, trunk, etc. | activate child safety locks doors lock up |
| lock_window | front, rear, driver_side, left_side, passenger_side, right_side | activate window child safety lock |
| lower_steering_wheel | adjust_type | move my steering wheel down |
| manual_default | | display vehicle diagnostics where is the driver's manual |
| manual_garage | | how do i program the garage remote |
| manual_set_memory | | can i save the passenger seat position save the driver seat memory two |
| manual_topic | help_feature | alarm help help cameras how do I adjust the headrest manual page for clock settings what is the recommended tire pressure for my car |
| music_player | player_action, album_title, artist, genre, podcast, song_title | play ,, find me some music by listen to , |
| navigation | navigation_location | how do I reach the nearest railway station best way to the closest park |
| no_command | *any* | *all unrecognized commands* |
| odometer_reset | | first trip counter to zero reset odometer |
| odometer_total | | current mileage how many miles on car |
| odometer_trip | | display trip distance what's the trip odometer |
| oil_level | number_unit | check oil level how much oil is left |
| open_door | front, rear, driver_side, left_side, passenger_side, right_side, fuel_door, garage_door, roof, side_door, van_door, percentage_value, roof | front right door open my sliding doors pop open open up all of the doors |
| open_glove_box | glove_box | lower the glove compartment open the cubby hole |
| open_hood | hood, hazard_lights | bonnet open please open the hood |
| open_trunk | trunk, rear | boot open my tailgate door pop open open the barn doors |
| open_window | front, rear, driver_side, left_side, passenger_side, right_side, roof, percentage_value, adjust_type, number_unit, length_unit adjust_type, number_unit, length_unit | roll down my windows crack the moonroof open lower windows by twenty five percent |
| query_airbag | driver_side, passenger_side, right_side, left_side | is the passenger airbag engaged |
| query_blinker | right_side, left_side, driver_side, passenger_side | are my blinkers on turn signal status |
| query_car_mode | car_mode | car mode status what's the car mode |
| query_cruise_control | speed_unit | what is the cruise set at what speed is the cruise on |
| query_date | date | what is today's date |
| query_defrost | front, rear | is front defrost on what is the status of the rear defrost |
| query_door_lock | front, rear, driver_side, left_side, passenger_side, right_side, roof, safety_lock, fuel_door, garage_door, van_door, trunk, hood, glove_box | are the back doors locked did i lock the car is the child-safety lock on |
| query_door_open | front, rear, driver_side, left_side, passenger_side, right_side, roof, safety_lock, fuel_door, garage_door, van_door, trunk, hood, glove_box | is the fuel door open is the hood closed did i remember to shut the garage door which doors are open |
| query_fan | fan_direction | is the fan set to footwell where is the air blowing |
| query_fan | front, rear | are the fans on what is the fan speed |
| query_lane_assist | | is the lane keeping aid active |
| query_light | automatic_lights, dashboard_lights, daytime_running_lights, door_lights, fog_lights, hazard_lights, high_beams, interior_lights, low_beams, parking_lights, light, front, rear, driver_side, left_side, passenger_side, right_side, duration, percentage_value, trunk | did i leave the low beams on is the dome light on what is the status of the daytime running lights |
| query_park_assist | | is the parking assistant on |
| query_parking_brake | | is the parking brake engaged |
| query_radio_station | | what channel is this |
| query_seat_warmers | front, rear, driver_side, left_side, passenger_side, right_side, percentage_value, adjust_type | are the heated seats on is the front right heated seat on |
| query_speed_limit | | what's the speed limit here |
| query_steer_assist | | is the steering assistang engaged |
| query_temperature | driver_side, passenger_side, hvac, percentage_value | check how cold is it inside check temp in the car tell me the current temperature of the car |
| query_temperature_outside | date | check exterior temperature today for me how hot is it outside my car |
| query_time | time_zone | what time is it in berlin what's the time now |
| query_timer | | how much left on the timer |
| query_volume | | how loud is the radio what is the volume |
| query_warning_light | | check dashboard lights describe dashboard warning tell me what is that light |
| query_weekday | date | what day is it today what's today |
| query_window | front, rear, driver_side, left_side, passenger_side, right_side, roof, percentage_value, adjust_type, number_unit, length_unit | is the back right window open are any windows open |
| query_wipers | front, rear | are the wipers on what is the speed of the wipers |
| query_year | | what year is it |
| raise_steering_whell | | move my steering wheel closer raise steering wheel up a bit |
| range | | distance until empty how far before in need to refuel |
| reset_demo | | reset the demo start over |
| scan_radio | | scan the fm radio search for radio stations |
| seat_backwards | front, rear, driver_side, left_side, passenger_side, right_side, center, length_unit, percentage_value | adjust driver seat back move driver seat backwards |
| seat_cooling | front, rear, driver_side, left_side, passenger_side, right_side, center, length_unit, percentage_value | activate seat cooling increase seat ventilation |
| seat_custom | front, rear, driver_side, left_side, passenger_side, right_side, center, length_unit, percentage_value | adjust seat to preset one disable passenger seat suspension switch my driver's seat to saved position four |
| seat_forward | front, rear, driver_side, left_side, passenger_side, right_side, center, length_unit, percentage_value | move driver seat forward |
| seat_incline | front, rear, driver_side, left_side, passenger_side, right_side, center, length_unit, percentage_value | move front seat back up sit up straighter |
| seat_lower | front, rear, driver_side, left_side, passenger_side, right_side, center, length_unit, percentage_value | lower my seat two inches |
| seat_raise | front, rear, driver_side, left_side, passenger_side, right_side, center, length_unit, percentage_value | lift up my seat make my seat taller |
| seat_recline | front, rear, driver_side, left_side, passenger_side, right_side, center, length_unit, percentage_value | lay the seat back recline the passenger seatback |
| send_message | contact_name, message | message matt i'm on my way ask batty by text are you free for dinner compose note to john in gchat dm whitney |
| service_reminder | duration, time, date, number_unit, percentage_value, time_of_day | am i scheduled for an oil change soon begin charge at two a m schedule an appointment for a tune up |
| set_car_mode | car_mode | activate traction mode enable sports mode |
| set_cruise_control | speed_unit, adjust_type, percentage_value, number_unit | cruise control set to seventy eight set cruise control feature down to fifty five |
| set_display | rear, front | adjust the screen settings |
| set_fan | cabin_vent, dual_air, floor_vent, windshield_vent, driver_side, percentage_value | blow are on my feet direct air flow to the windshield |
| set_fan | front, rear, driver_side, left_side, passenger_side, right_side, hvac, adjust_type, percentage_value, duration, number_unit, safety_lock duration, number_unit, safety_lock | activate max a c adjust fan speed to low setting change the fan to four |
| set_lights | automatic_lights, dashboard_lights, daytime_running_lights, door_lights, fog_lights, hazard_lights, high_beams, interior_lights, low_beams, parking_lights, light, front, rear, percentage_value, driver_side, left_side, passenger_side, right_side, trunk | chage cab light to max intensity |
| set_off_car_mode | car_mode | cancel hill start assist cut off auto pilot |
| set_radio | radio_station, genre | change station to w i p b listen to radio station a m ten seventy |
| set_seat_warmers | front, rear, driver_side, left_side, passenger_side, right_side, adjust_type, percentage_value | both seat warmers to three can you turn my seat heater on medium change warmers highest speed |
| set_steering_wheel_warmer | | |
| set_temperature | adjust_type, percentage_value, front, rear, driver_side, passenger_side, hvac, number_unit, temperature_unit | a c at seventy two degrees change front heater setting to low make the temperature sixty two degrees fahrenheit |
| set_time | | reset the clock |
| set_volume | adjust_type, artist, music_service, song_title | change audio volume zero mute music |
| set_volume | adjust_type, percentage_value, front, rear, number_unit, front, rear, number_unit | adjust the volume change audio to fifty percent make volume level three |
| set_wipers | front, rear, percentage_value, number_unit | all the wipers high my rear wiper highest |
| speed_limiter | | activate speed limiter decrease the governor increase limiter to forty five miles per hour |
| timer_on | duration | set a timer for ten minutes |
| timer_off | | cancel timer |
| tire_pressure | front, rear, driver_side, left_side, passenger_side, right_side | are my tires flat what is my front right tire pressure |
| turn_off_airbag | driver_side, passenger_side, left_side, right_side | activate passenger side airbag |
| turn_off_blinker | side | blinkers off deactivate left turn signal |
| turn_off_bluetooth | | bluetooth disconnect car device delete my bluetooth pairing for android |
| turn_off_car | | cut the engine disable vehicle |
| turn_off_cruise_control | | cancel cruise control |
| turn_off_defrost | front, rear, driver_side, left_side, passenger_side, right_side, percentage_value, adjust_type | all my back glass defroster off stop defroster |
| turn_off_display | rear, front | turn off the screens |
| turn_off_fan | front, rear, hvac, adjust_type, percentage_value | a c off can you turn off the heat cut fan |
| turn_off_lane_assist | | turn off lane assist deactivate l d w |
| turn_off_navigation | | quit g p s stop navigation |
| turn_off_park_assist | | turn off parking assistant |
| turn_off_parking_brake | roof | release e brake |
| turn_off_radio | | turn off radio |
| turn_off_seat_warmers | front, rear, driver_side, left_side, passenger_side, right_side | all seat warmers off disengage right seat's seat warmers |
| turn_off_steer_assist | | disengage steering assistant |
| turn_off_steering_wheel_warmer | | |
| turn_off_wipers | front, rear | back wipers off deactivate all wipers |
| turn_on_airbag | driver_side, passenger_side, left_side, right_side | |
| turn_on_blinker | side | left blinker on turn on the right blinker |
| turn_on_bluetooth | | engage bluetooth set up bluetooth |
| turn_on_car | | begin engine start the car |
| turn_on_cruise_control | | begin cruise control feature enable cruise contol |
| turn_on_defrost | front, rear, driver_side, left_side, passenger_side, right_side, percentage_value, adjust_type | activate front defrost only demist rear windshield |
| turn_on_display | rear, front | turn on the heads up display can you turn on the rear tv screens turn on the kids screens |
| turn_on_fan | front, rear, hvac | activate a c initiate heater power on fan |
| turn_on_lane_assist | | activate l t a turn on lane keeping aid |
| turn_on_navigation | | begin navigation start the g p s |
| turn_on_park_assist | | park the car turn on parking sensors |
| turn_on_parking_brake | | activate parking brake engage hand brake |
| turn_on_radio | | turn on the radio |
| turn_on_seat_warmers | front, rear, driver_side, left_side, passenger_side, right_side | activate front left seat's seat heaters both seat heaters on |
| turn_on_steer_assist | | begin steer control |
| turn_on_steering_wheel_warmer | | |
| turn_on_wipers | front, rear | activate front wiper turn on rear wiper |
| unlock_door | front, rear, driver_side, left_side, passenger_side, right_side, roof, safety_lock, fuel_door, garage_door, van_door, trunk, hood, glove_box | all door child locks disable driver side door unlock |
| unlock_window | front, rear, driver_side, left_side, passenger_side, right_side | all my windows child lock off |
| warning_light._specific | warning_light | check engine light provide information regarding blinking check engine light on dashboard what does the green oil light indicate |
| wash_window | front, rear | clean all back glass mist my front windshield |
| washer_fluid_level | | check washer fluid level |
## Templates
Templates add functionality to recognizer models. This includes running models
simultaneously or sequentially, and adding VAD audio gating.
See [template types](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) for an overview.
### tpl-spot-concurrent-1.5.0.snsr
Runs two [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) models at the same time.
**Also see these related items:** [tpl-spot-concurrent](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-concurrent.md#tpl-spot-concurrent-type)
### tpl-spot-debug-1.5.1.snsr
Adds runtime data collection to a [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) model.
**Also see these related items:** [tpl-spot-debug](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-debug.md#tpl-spot-debug-type)
### tpl-spot-select-1.4.0.snsr
Dynamically selects which of the two embedded [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type)
models to run.
**Also see these related items:** [tpl-spot-select](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-select.md#tpl-spot-select-type)
### tpl-spot-sequential-1.5.0.snsr
Runs two [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) models one after the other, with optional
looping on the second. Includes push-to-talk as an alternative to the wake word.
**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)
### tpl-spot-vad-3.13.0.snsr
Runs a [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) until it spots, then does start-
and endpoint detection on the subsequent audio stream using
a [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type).
**Also see these related items:** [tpl-spot-vad](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad.md#tpl-spot-vad-type)
### tpl-opt-spot-vad-lvcsr-1.28.0.snsr _(tnl)_
Optionally runs a [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) until it spots, segments the subsequent
audio stream with a [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type), then sends the segmented audio to
an [LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type) or [STT](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type) recognizer. You can select at runtime
whether recognition waits on the wake word or starts immediately.
**Also see these related items:** [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-3.23.0.snsr _(tnl)_
Runs a [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) until it spots, segments the subsequent
audio stream with a [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type), then sends the segmented audio to
an [LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type) or [STT](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type) recognizer.
**Also see these related items:** [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad-lvcsr.md#tpl-spot-vad-lvcsr-type)
### tpl-vad-lvcsr-3.17.0.snsr
Detects speech with a [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type) and sends the segmented audio to
an [LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type) or [STT](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type) recognizer.
**Also see these related items:** [tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-vad-lvcsr.md#tpl-vad-lvcsr-type)
*[API]: Application Programming Interface
*[EFT]: Enrolled Fixed Trigger: fixed wake words adapted to a speaker to improve accuracy
*[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
*[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
*[UDT]: User-Defined Trigger: enrolled wake words and command sets
*[VAD]: Voice Activity Detector
---
source_path: "models/tpl/index.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/tpl/"
---
# Templates
Task templates are models that use composition to add behavior to
[basic model types](https://doc.sensory.com/tnl/7.8/models/types/index.md#model-types). Templates have _slots_ that you can fill with any
model that has a [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) that matches what the slot expects.
The [tpl-spot-vad-lvscr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad-lvcsr.md#tpl-spot-vad-lvcsr-type) template, for example,
waits for the [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type)
in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0), then runs the [LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type) or [STT](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type) model in slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1).
The composed model has [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 implements all of the
events and settings expected of such a model type. You can use it as a drop-in replacement
for a wake word in (say) [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spotc) without any code changes.
Compose new template-based models with [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit), on the fly with [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval), or
by using the [setStream](https://doc.sensory.com/tnl/7.8/api/inference.md#setters) function at runtime.
## Composed models
[tpl-spot-concurrent](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-concurrent.md#tpl-spot-concurrent-type)
- Runs two [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) models at the same time. It provides a convenient way to create a single
wake word model that has the combined vocabulary of two other models.
[tpl-spot-debug](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-debug.md#tpl-spot-debug-type)
- Adds runtime data collection to a [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) model. Use this to collect audio and event timings
from an embedded model, [snsr-log-split](https://doc.sensory.com/tnl/7.8/tools/snsr-log-split.md#snsr-log-split) to extract audio, event logs, and the model itself from the generated
log file, and [audio-check](https://doc.sensory.com/tnl/7.8/tools/audio-check.md#audio-check) to verify audio recording quality.
[tpl-spot-select](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-select.md#tpl-spot-select-type)
- Allows you to dynamically select which of the two embedded [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) models to run.
[tpl-spot-sequential](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-sequential.md#tpl-spot-sequential-type)
- Runs two [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) models in sequence. Use this to listen for a trigger phrase followed by
a command, for example: "Voice genie, play music."
[tpl-spot-vad](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad.md#tpl-spot-vad-type)
- Runs the [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0) until it detects, then does start- and endpoint detection
with a [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type) on the audio stream following the wake word.
[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) _(tnl)_
- _Optionally_ runs the [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0) until it detects, then segments the audio
following the wake word with a [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type) and sends the segmented audio to the [LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type) or
[STT](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type) recognizer in slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1).
[tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad-lvcsr.md#tpl-spot-vad-lvcsr-type) _(tnl)_
- Runs the [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0) until it detects, segments the audio following the wake
word with a [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type), and sends the segmented audio to the [LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type) or [STT](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type)
recognizer in slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1).
[tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-vad-lvcsr.md#tpl-vad-lvcsr-type) _(tnl)_
- Detects speech with a [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type) and sends the segmented audio to the [LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type)
or [STT](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type) recognizer in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0).
*[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: "models/tpl/tpl-opt-spot-vad-lvcsr.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/tpl/tpl-opt-spot-vad-lvcsr/"
---
# tpl-opt-spot-vad-lvcsr _(tnl)_
This [template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) _optionally_ runs the [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0)
until it detects, then segments the audio following the wake word with a [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type)
and sends the segmented audio to the [LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type) or [STT](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type)
recognizer in slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1).
[slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot) controls whether `tpl-opt-spot-vad-lvcsr` waits for the wake word:
* With `slot == 0` it waits for the wake word before starting the VAD.
In this mode the behavior is that of [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad-lvcsr.md#tpl-spot-vad-lvcsr-type).
* With `slot == 1` starts the VAD immediately and the behavior is that of [tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-vad-lvcsr.md#tpl-vad-lvcsr-type).
You can change [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot) at runtime. Use this to gate only the first of a series of commands
with a wake word.
`tpl-spot-vad-lvcsr` has [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).
Expected [task types](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type):
* **Slot 0:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
* **Slot 1:** [lvcsr](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#lvcsr)
**Also see these related items:** [tpl-opt-spot-vad-lvcsr-1.28.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-opt-spot-vad-lvcsr), [tpl-spot-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad-lvcsr.md#tpl-spot-vad-lvcsr-type), [tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-vad-lvcsr.md#tpl-vad-lvcsr-type)
## Operation
```mermaid
flowchart TD
start((start))
slotCheck0{slot == 0?}
start --> slotCheck0
slotCheck0 -->|yes| startWW
slotCheck0 -->|no| fetch0
subgraph slot0[slot 0 (phrasespot)]
startWW((start))
fetchWW[/samples from ->audio-pcm/]
audioWW(^sample-count)
processWW[process]
result(0.^result)
stopWW((stop))
startWW --> fetchWW
fetchWW --> audioWW
audioWW --> processWW
processWW --> fetchWW
processWW -->|recognize| result
result --> stopWW
end
subgraph slot1[slot 1 (lvcsr)]
startSTT((start))
startSTTfinal((start))
stopSTT((stop))
stopSTTpartial((stop))
processSTT[process]
partialSTT(^result-partial)
intentSTT(^nlu-intent)
slotSTT(^nlu-slot)
resultSTT(^result)
nluSTT{NLU match?}
slmSTT{SLM included?}
generateSTT[generate]
slmstartSTT(^slm-start)
slmresultpartialSTT(^slm-result-partial)
slmresultSTT(^slm-result)
startSTT --> processSTT
processSTT ---->|hypothesis| partialSTT
partialSTT --> stopSTTpartial
startSTTfinal --> nluSTT
nluSTT -->|yes| intentSTT
nluSTT -->|no| resultSTT
intentSTT --> slotSTT
slotSTT --> resultSTT
slotSTT -->|more| intentSTT
resultSTT --> slmSTT
slmSTT -->|yes| slmstartSTT
slmSTT -->|no| stopSTT
slmstartSTT -->|OK| generateSTT
slmstartSTT -->|STOP| stopSTT
generateSTT -->|response| slmresultpartialSTT
slmresultpartialSTT --> generateSTT
generateSTT -->|done| slmresultSTT
slmresultSTT --> stopSTT
end
listenBegin(^listen-begin)
listenEnd(^listen-end)
stopWW --> listenBegin
listenBegin --> fetch0
fetch0[/samples from ->audio-pcm/]
fetch1[/samples from ->audio-pcm/]
audio0(^sample-count)
audio1(^sample-count)
silence(^silence)
begin(^begin)
END(^end)
limit(^limit)
process0[VAD process]
process1[VAD process]
final@{ shape: f-circ }
slotCheck1{slot == 0?}
fetch0 --> audio0
audio0 --> process0
process0 --> fetch0
process0 -->|speech start| begin
process0 -->|timeout| silence
silence ~~~ final
silence --> slotCheck1
begin --> fetch1
fetch1 --> audio1
audio1 --> process1
process1 --> startSTT
stopSTTpartial --> fetch1
process1 -->|speech end| END
process1 -->|speech limit| limit
END --> final
limit --> final
final --> startSTTfinal
stopSTT --> slotCheck1
slotCheck1 -->|no| fetch0
slotCheck1 -->|yes| listenEnd
listenEnd --> startWW
```
Operation flow.
1. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
2. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
3. If processing does not detect a wake word, continue at step 1.
4. Invoke [0.^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) for the wake word.
5. Invoke [^listen-begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-begin) and start VAD processing.
6. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
7. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
8. If VAD processing does not detect the start of speech within the [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence) timeout, invoke [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence) and continue at step 15.
9. Invoke [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin) if processing detects the start of speech, else continue at step 6.
10. Read audio date from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
11. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
12. If VAD processing detects an endpoint invoke either [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit) or [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end) and continue at step 14.
13. Process VAD segmented audio in the LVCSR or STT recognizer
* Invoke [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) with interim recognition result hypothesis.
* Continue at step 10.
14. Produce a final LVCSR or STT recognition hypothesis.
* Invoke [^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) for each NLU intent found.
* Invoke [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) with the final recognition hypothesis.
* If there's no SLM, continue at step 15.
* Invoke [^slm-start](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-start), if the callback returns [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop), continue at step 15.
* Generate SLM result, invoking [^slm-result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result-partial) on each generated token.
* Invoke [^slm-result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result) with complete SLM result.
15. Invoke [^listen-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-end) and start listening for the wake word again at step 1.
Register callback handlers with [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) only for those events you're interested in.
## Settings
**Available 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), [^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), [^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), [^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), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event), [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence), [^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-start](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-start)
**Available iterators:** [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator), [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator)
**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)
**Available runtime settings:** [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), [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)
**Available configuration settings:** [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [backlog-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backlog-interval), [backoff](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backoff), [custom-vocab](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#custom-vocab), [delay](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#delay), [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms), [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), [include-wake-word-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-wake-word-audio), [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence), [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point), [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording), [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point), [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval), [samples-per-second](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#samples-per-second), [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot), [stt-profile](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#stt-profile), [sv-threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#sv-threshold), [wake-word-at-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#wake-word-at-end)
**Available values:** [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)
**Also see these related items:** [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spot-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code), [PhraseSpot.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-code)
## Notes
Use this template for command and control type applications where commands are
initiated with a wake word in certain contexts and not in others.
We recommend that you set [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot)`= 1` in the [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) handler, and [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot)`= 0` in
the [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence) handler. With this configuration the recognizer requires a wake word to start
listening only for the first in a series of interactions. After this it will revert to requiring
a wake word only if the user does not say anything for at least [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence) ms.
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), and [trailing-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#trailing-silence)
apply to both slot 0 and slot 1, but [include-leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-leading-silence) applies only to slot 0.
Set [include-wake-word-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-wake-word-audio)` = 1` to include the wake word audio in the
samples passed to the LVCSR or STT recognizer. STT hypotheses do not include the wake word
text unless Sensory specifically configured the model to do so.
The [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) and [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) events are for the LVCSR or STT recognizer
in slot 1. If you need direct access to the wake word result, prefix the event
with the slot path: `0.^result` Use the slot prefix to read values in the `0.^result` event handler too, for example call [getString](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) with key [0.text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) to read the wake word transcription.
## Examples
### Select wake-word or VAD-only behavior
```console
% cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9
% bin/snsr-edit -o opt-vg-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
# Say "Voice genie, open the sunroof."
% snsr-eval -vt opt-vg-stt.snsr
Using live audio from default capture device. ^C to stop.
P 33010 33490 (0.3201) Open the sun
P 33050 33890 (0.7712) Open the sunroof
32010 34185 [^end] VAD speech region.
NLU intent: open_window (0.9956) = open the sunroof
NLU entity: roof (0.9595) = sunroof
33050 33890 (0.5731) Open the sunroof.
^C
# Select the VAD-only path with slot=1
# Say "Close all the windows"
% snsr-eval -vt opt-vg-stt.snsr -s slot=1
Using live audio from default capture device. ^C to stop.
P 2150 2670 (0.257) Clothes. All
P 2190 3150 (0.7631) Close. All the wind
P 2190 3430 (0.9899) Close all the windows
1950 3855 [^end] VAD speech region.
NLU intent: close_window (0.9977) = close all the windows
2190 3470 (0.9244) Close all the windows.
^C
```
### Use trailing wake-word _(since [7.7.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.7.0))_
Recognize a phrase with the wake word at either end of an utterance.
```console
% cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9
% bin/snsr-edit -o opt-vg-stt-vg.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\
-s wake-word-at-end=1
# Say "Voice genie, set the radio to 91.5 FM."
% bin/snsr-eval -vt opt-vg-stt-vg.snsr
Using live audio from default capture device. ^C to stop.
P 4360 5000 (0.2927) Set. The radio
P 4400 5280 (5.7e-07) Set the radio to n
P 4400 5760 (0.7336) Set the radio to ninety-one
P 4400 6120 (0.6005) Set the radio to ninety one point
P 4400 6440 (0.5195) Set the radio to ninety one point. Five
P 4400 6480 (0.6733) Set the radio to ninety one point. Five
3405 7455 [^end] VAD speech region.
NLU intent: set_radio (0.9674) = set the radio to 91.5 FM
NLU entity: radio_station (0.9688) = 91.5 FM
4400 7080 (0.3896) Set the radio to ninety one point. Five F. M.
15225 17490 [^end] VAD speech region.
# Say "Will it rain in Portland tomorrow, Voice Genie?"
NLU intent: no_command (0.9977) = will it rain in portland tomorrow
NLU entity: time (0.9773) = tomorrow
15460 17260 (0.6731) Will it rain in Portland tomorrow?
^C
```
*[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
*[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/tpl/tpl-spot-concurrent.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-concurrent/"
---
# tpl-spot-concurrent
This [template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) runs two [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) models at
the same time. It provides a convenient way to create a single wake word model
that has the combined vocabulary of two other models.
`tpl-spot-concurrent` has [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).
Expected [task types](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type):
* **Slot 0:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
* **Slot 1:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
**Also see these related items:** [tpl-spot-concurrent-1.5.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-concurrent)
## Operation
```mermaid
flowchart TD
start((start))
fetch[/samples from ->audio-pcm/]
audio(^sample-count)
split@{ shape: f-circ }
join@{ shape: f-circ }
start --> fetch
fetch --> audio
audio --> split
split --> start0
split --> start1
end0 --> join
end1 --> join
join ----> fetch
subgraph slot0[slot 0 (phrasespot)]
start0((start))
process0[process]
result0(^result)
end0((stop))
start0 --> process0
process0 --> end0
process0 -->|recognize| result0
result0 --> end0
end
subgraph slot1[slot 1 (phrasespot)]
start1((start))
process1[process]
result1(^result)
end1((stop))
start1 --> process1
process1 --> end1
process1 -->|recognize| result1
result1 --> end1
end
```
Operation flow.
1. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
2. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
3. Send audio samples to recognizers in slot 0 and slot 1.
4. Invoke [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) if processing detects a vocabulary phrase.
5. Continue processing until [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end) occurs on [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm),
or one of the event handlers returns a code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok).
Register callback handlers with [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) only for those events you're interested in.
## Settings
**Available events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event)
**Available iterators:** _none_
**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)
**Available runtime settings:** [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), [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)
**Available configuration settings:** [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), [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [samples-per-second](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#samples-per-second)
**Available values:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
**Also see these related items:** [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spot-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code), [PhraseSpot.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-code), [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudio-code)
## Notes
Runs the wake word models 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) at the same
time, in the same thread.
The two recognizers are entirely independent, and can produce
results that overlap in time. For production use Sensory recommends
custom multi-phrase wake word recognizers instead. These have improved
false reject / false accept performance.
The combined model is a [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type), and can be used
in any application that expects such a model without API changes.
Configuration settings and iterators are not available in the
combined model. You can access these for the individual models
by prefixing the setting path with the slot. For example,
use `0.operating-point` to read or change the [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) of the first spotter
and use `1.operating-point` to read or change the [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) of the second spotter.
Attempting to set [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) without a slot prefix will result in an error.
```console
% cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9
% bin/snsr-edit -o vg-hbg.snsr\
-t 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
% bin/snsr-edit \
-t vg-hbg.snsr \
-s operating-point=5
Setting "operating-point" not found, did you mean "0.operating-point" or "1.operating-point"?
```
Change individual settings at runtime by prefixing the
setting name with the slot:
**C/C++**
```c
/* Set the operating point for spotter 0 only. */
snsrSetInt(session, SNSR_SLOT_0 SNSR_OPERATING_POINT, 7);
```
**Java**
```java
/* Set the operating point for spotter 0 only. */
session.setInt(Snsr.SLOT_0 + Snsr.OPERATING_POINT, 7);
```
You can recombine combined models and nest them to an arbitrary depth to
run any number[^1] of wake word recognizers at the same time:
[^1]: Limited only by available RAM and CPU.
```console
% cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9
% bin/snsr-edit -o models1-4.snsr\
-t model/tpl-spot-concurrent-1.5.0.snsr\
-f 0 model/tpl-spot-concurrent-1.5.0.snsr\
-f 0.0 model-1.snsr\
-f 0.1 model-2.snsr\
-f 1 model/tpl-spot-concurrent-1.5.0.snsr\
-f 1.0 model-1.snsr\
-f 1.1 model-2.snsr
```
In this example, the four wake word models are located in the `0.0`, `0.1`,
`1.0` and `1.1` slots
## Examples
```console
% cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9
% bin/snsr-edit -o vg-hbg.snsr\
-t 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
% bin/snsr-eval -t vg-hbg.snsr
2370 2940 voicegenie
5805 6420 voicegenie
7740 8640 hello blue genie
10440 11100 voicegenie
12060 12870 hello blue genie
^C
```
*[API]: Application Programming Interface
*[RAM]: Random Access Memory
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
---
source_path: "models/tpl/tpl-spot-debug.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-debug/"
---
# tpl-spot-debug
This [template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) adds runtime data collection to a [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type)
model. Use this to collect audio and event timings from an embedded model,
[snsr-log-split](https://doc.sensory.com/tnl/7.8/tools/snsr-log-split.md#snsr-log-split) to extract audio, event logs, and the model itself from the generated
log file, and [audio-check](https://doc.sensory.com/tnl/7.8/tools/audio-check.md#audio-check) to verify audio recording quality.
`tpl-spot-debug` has [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).
Expected [task types](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type):
* **Slot 0:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
**Also see these related items:** [tpl-spot-debug-1.5.1.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-debug)
## Operation
```mermaid
flowchart TD
start0((start))
log@{ shape: doc, label: "debug-log-file" }
start0 --> start
slot0 -.-> log
subgraph slot0[slot 0 (phrasespot)]
start((start))
fetch[/samples from ->audio-pcm/]
audio(^sample-count)
process
result(^result)
start --> fetch
fetch --> audio
audio --> process
process --> fetch
process -->|recognize| result
result --> fetch
end
```
Operation flow.
1. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
2. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
3. Invoke [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) if processing detects a vocabulary phrase.
4. Continue processing until [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end) occurs on [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm),
or one of the event handlers returns a code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok).
Register callback handlers with [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) only for those events you're interested in.
## Settings
**Available events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event)
**Available iterators:** [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator), [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator)
**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)
**Available runtime settings:** [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), [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), [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)
**Available configuration settings:** [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0), [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [debug-log-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#debug-log-file), [delay](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#delay), [dsp-target](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-target), [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms), [include-model](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-model), [listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window), [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), [samples-per-second](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#samples-per-second), [sv-threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#sv-threshold)
**Available values:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
**Also see these related items:** [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spot-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code), [PhraseSpot.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-code), [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudio-code)
## Notes
You must specify the name of the log file with [debug-log-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#debug-log-file).
[include-model](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-model) controls whether the log file includes a copy
of the original task model. This is enabled by default.
The combined model is a [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) that you can use as a
drop-in replacement for the original wake word without any API changes.
Log files include time-stamped entries with:
* SDK library information,
* the spotter model being used,
* audio samples, and
* event callbacks.
Extract text, model and audio data from the log file with the [snsr-log-split](https://doc.sensory.com/tnl/7.8/tools/snsr-log-split.md#snsr-log-split) utility.
## Examples
```console
% cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9
% bin/snsr-edit -o hbg-debug.snsr\
-t model/tpl-spot-debug-1.5.1.snsr\
-f 0 model/spot-hbg-enUS-1.4.0-m.snsr\
-s debug-log-file=hbg-debug.snsrlog
% bin/snsr-eval -t hbg-debug.snsr
2925 3690 hello blue genie
4995 5790 hello blue genie
7920 8640 hello blue genie
^C
# The error below is harmless and expected because we
# interrupted snsr-eval with ^C
% bin/snsr-log-split -vv hbg-debug.snsrlog
Writing to './'
Processing hbg-debug.snsrlog
-> audio ./hbg-debug.wav
-> event ./hbg-debug.txt
-> model ./hbg-debug.snsr
Error: Input file "hbg-debug.snsrlog" is truncated.
Processed 1273 items.
```
*[API]: Application Programming Interface
*[FR]: False Reject: the recognizer did not trigger when the target phrase was spoken
*[SDK]: Software Development Kit
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
---
source_path: "models/tpl/tpl-spot-select.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-select/"
---
# tpl-spot-select
This [template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) allows you to dynamically select which of the
two embedded [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) models to run.
`tpl-spot-select` has [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).
Expected [task types](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type):
* **Slot 0:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
* **Slot 1:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
**Also see these related items:** [tpl-spot-select-1.4.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-select)
## Operation
```mermaid
flowchart TD
start((start))
fetch[/samples from ->audio-pcm/]
audio(^sample-count)
join@{ shape: f-circ }
start --> fetch
fetch --> audio
audio -->|slot == 0| start0
audio -->|slot == 1| start1
end0 --> join
end1 --> join
join ----> fetch
subgraph slot0[slot 0 (phrasespot)]
start0((start))
process0[process]
result0(^result)
end0((stop))
start0 --> process0
process0 --> end0
process0 -->|recognize| result0
result0 --> end0
end
subgraph slot1[slot 1 (phrasespot)]
start1((start))
process1[process]
result1(^result)
end1((stop))
start1 --> process1
process1 --> end1
process1 -->|recognize| result1
result1 --> end1
end
```
Operation flow.
1. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
2. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
3. Send audio to the recognizer specified by [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot).
5. Invoke [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) if processing detects a vocabulary phrase.
6. Continue processing until [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end) occurs on [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm),
or one of the event handlers returns a code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok).
Register callback handlers with [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) only for those events you're interested in.
## Settings
**Available events:** [^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), [^new-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#new-user), [^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), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event)
**Available iterators:** _none_
**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)
**Available runtime settings:** [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), [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), [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)
**Available configuration settings:** [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), [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [samples-per-second](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#samples-per-second), [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot)
**Available values:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
**Also see these related items:** [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spot-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code), [PhraseSpot.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-code), [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudio-code)
## Notes
Use [slot](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#slot) to select either the spotter 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).
Use this template to reduce the model size when an application uses variants
of the same recognizer in different contexts. This reduces the overall model
size and RAM requirements as identical objects are shared between the slots.
The combined model is a [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type), and can be used
in any application that expects such a model without API changes.
Configuration settings and iterators are not available in the
combined model. You can access these for the individual models
by prefixing the setting path with the slot. For example,
use `1.operating-point` to read or change the [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point)
of the second spotter.
Change individual settings at runtime by prefixing the
setting name with the slot:
**C/C++**
```c
/* Set the operating point for spotter 0 only. */
snsrSetInt(session, SNSR_SLOT_0 SNSR_OPERATING_POINT, 7);
```
**Java**
```java
/* Set the operating point for spotter 0 only. */
session.setInt(Snsr.SLOT_0 + Snsr.OPERATING_POINT, 7);
```
## Examples
```console
% cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9
% bin/snsr-edit -o vg-hbg-select.snsr\
-t model/tpl-spot-select-1.4.0.snsr\
-f 0 model/spot-voicegenie-enUS-6.5.1-m.snsr\
-f 1 model/spot-hbg-enUS-1.4.0-m.snsr
# repeat "hello blue genie" and "voice genie"
% bin/snsr-eval -t vg-hbg-select.snsr -s slot=0
3480 4140 voicegenie
9945 10545 voicegenie
^C
# repeat "hello blue genie" and "voice genie"
% bin/snsr-eval -t vg-hbg-select.snsr -s slot=1
1635 2460 hello blue genie
6210 6870 hello blue genie
^C
```
*[API]: Application Programming Interface
*[RAM]: Random Access Memory
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
---
source_path: "models/tpl/tpl-spot-sequential.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-sequential/"
---
# tpl-spot-sequential
This [template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) runs two [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) models
in sequence. Use this to listen for a trigger phrase followed by a command,
for example: "Voice genie, play music."
`tpl-spot-sequential` has [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).
Expected [task types](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type):
* **Slot 0:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
* **Slot 1:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
**Also see these related items:** [tpl-spot-sequential-1.5.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-concurrent)
## Operation
```mermaid
flowchart TD
start((start))
loop0{loop == 2?}
start --> loop0
loop0 -->|no| start0
loop0 -->|yes| start1
subgraph slot0[slot 0 (phrasespot)]
start0((start))
fetch0[/samples from ->audio-pcm/]
audio0(^sample-count)
process0[process]
stop0((stop))
start0 --> fetch0
fetch0 --> audio0
audio0 --> process0
process0 --> fetch0
process0 -->|recognize| stop0
end
listenBegin(^listen-begin)
stop0 --> listenBegin
listenBegin --> start1
subgraph slot1[slot 1 (phrasespot)]
start1((start))
fetch1[/samples from ->audio-pcm/]
audio1(^sample-count)
process1[process]
result1(^result)
stop1((stop))
loop{loop == 0?}
loop2{loop == 2?}
start1 --> fetch1
fetch1 --> audio1
audio1 --> process1
process1 --> fetch1
process1 --->|recognize| result1
process1 -->|timeout| loop2
loop2 -->|no| stop1
loop2 -->|yes| fetch1
result1 --> loop
loop -->|no| fetch1
loop -->|yes| stop1
end
listenEnd(^listen-end)
stop1 --> listenEnd
listenEnd --> start0
```
Operation flow.
1. If [loop](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#loop) `== 2` skip to step 6.
2. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
3. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
4. Invoke [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) if processing detects a vocabulary phrase, else continue at step 2.
5. Invoke [^listen-begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-begin), then start the wake word in slot 1.
6. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
7. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
8. If [loop](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#loop) `!= 2` and processing does not detect a wake word within
[listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window), invoke [^listen-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-end) and restart the slot 0 wake word at step 2.
9. Invoke [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) if processing detects a vocabulary phrase, else continue at step 6.
10. If [loop](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#loop) `== 0` invoke [^listen-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-end) and continue at step 2.
11. If [loop](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#loop) `!= 0` reset the listen-window timeout and continue processing
at step 6.
12. Continue processing until [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end) occurs on [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm),
or one of the event handlers returns a code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok).
Register callback handlers with [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) only for those events you're interested in.
## Settings
**Available events:** [^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), [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event)
**Available iterators:** [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator), [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator)
**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)
**Available runtime settings:** [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), [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), [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)
**Available configuration settings:** [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), [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [delay](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#delay), [dsp-target](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-target), [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms), [listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window), [loop](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#loop), [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), [samples-per-second](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#samples-per-second), [sv-threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#sv-threshold)
**Available values:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
**Also see these related items:** [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spot-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code), [PhraseSpot.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-code), [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudio-code)
## Notes
With [loop](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#loop) `== 0` (the default): This template
runs the spotter in slot `0` until it spots, then runs slot `1`
until it spots, or the [listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window) timeout expires, then
returns to the spotter in slot `0`.
With [loop](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#loop) `== 1`: This
runs the spotter in slot `0` until it spots, then runs slot `1`
until the [listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window) timeout expires, then returns to
the spotter in slot `0`. It resets the expiration timer every time
slot `1` recognizes.
_(since [7.6.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.6.0))_ With [loop](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#loop) `== 2`: The template runs only slot `1`.
If your application needs to listen for a wake word but also support
an external trigger, such as a push-to-talk button, set `loop=2`
when the event occurs.
The combined model is a [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) and can be used
in any application that expects those without code changes.
Combined model settings refer to the model in slot `1`,
so [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point) refers to `1.operating-point`.
You can change settings for the wake word in slot `0`
by prefixing the setting name with [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0), for example:
`0.operating-point`.
The model invokes [^listen-begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-begin) just before audio focus switches
to slot 1, and [^listen-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-end) before audio focus switches back to
slot 0. If there's no [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) between `^listen-begin` and `^listen-end`
it is because the recognizer in slot 1 timed out.
## Examples
```console
% cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9
% bin/snsr-edit -o vg-music.snsr\
-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
# say "voice genie, play music"
% bin/snsr-eval -vvt vg-music.snsr
Using live audio from default capture device. ^C to stop.
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"
3180 [^listen-begin]
phrase:
3630 4410 (1 sv) play_music
words:
3630 3900 (1 sv)
3900 4410 (1 sv) play_music
4635 [^listen-end]
^C
```
*[API]: Application Programming Interface
*[FR]: False Reject: the recognizer did not trigger when the target phrase was spoken
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
---
source_path: "models/tpl/tpl-spot-vad-lvcsr.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad-lvcsr/"
---
# tpl-spot-vad-lvcsr _(tnl)_
This [template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) runs the [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0)
until it detects, segments the audio following the wake word with a [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type),
and sends the segmented audio to the [LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type) or [STT](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type)
recognizer in slot [1](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#1).
This behavior is also available in the [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)
template, which adds an option to skip the wake word.
`tpl-spot-vad-lvcsr` has [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).
Expected [task types](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type):
* **Slot 0:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
* **Slot 1:** [lvcsr](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#lvcsr)
**Also see these related items:** [tpl-spot-vad-lvcsr-3.23.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad-lvcsr), [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)
## Operation
```mermaid
flowchart TD
start((start))
start --> startWW
subgraph slot0[slot 0 (phrasespot)]
startWW((start))
fetchWW[/samples from ->audio-pcm/]
audioWW(^sample-count)
processWW[process]
result(0.^result)
stopWW((stop))
startWW --> fetchWW
fetchWW --> audioWW
audioWW --> processWW
processWW --> fetchWW
processWW -->|recognize| result
result --> stopWW
end
subgraph slot1[slot 1 (lvcsr)]
startSTT((start))
startSTTfinal((start))
stopSTT((stop))
stopSTTpartial((stop))
processSTT[process]
partialSTT(^result-partial)
intentSTT(^nlu-intent)
slotSTT(^nlu-slot)
resultSTT(^result)
nluSTT{NLU match?}
slmSTT{SLM included?}
generateSTT[generate]
slmstartSTT(^slm-start)
slmresultpartialSTT(^slm-result-partial)
slmresultSTT(^slm-result)
startSTT --> processSTT
processSTT ---->|hypothesis| partialSTT
partialSTT --> stopSTTpartial
startSTTfinal --> nluSTT
nluSTT -->|yes| intentSTT
nluSTT -->|no| resultSTT
intentSTT --> slotSTT
slotSTT --> resultSTT
slotSTT -->|more| intentSTT
resultSTT --> slmSTT
slmSTT -->|yes| slmstartSTT
slmSTT -->|no| stopSTT
slmstartSTT -->|OK| generateSTT
slmstartSTT -->|STOP| stopSTT
generateSTT -->|response| slmresultpartialSTT
slmresultpartialSTT --> generateSTT
generateSTT -->|done| slmresultSTT
slmresultSTT --> stopSTT
end
listenBegin(^listen-begin)
listenEnd(^listen-end)
stopWW --> listenBegin
listenBegin --> fetch0
fetch0[/samples from ->audio-pcm/]
fetch1[/samples from ->audio-pcm/]
audio0(^sample-count)
audio1(^sample-count)
silence(^silence)
begin(^begin)
END(^end)
limit(^limit)
process0[VAD process]
process1[VAD process]
final@{ shape: f-circ }
fetch0 --> audio0
audio0 --> process0
process0 --> fetch0
process0 -->|speech start| begin
process0 -->|timeout| silence
silence ~~~ final
silence --> listenEnd
begin --> fetch1
fetch1 --> audio1
audio1 --> process1
process1 --> startSTT
stopSTTpartial --> fetch1
process1 -->|speech end| END
process1 -->|speech limit| limit
END --> final
limit --> final
final --> startSTTfinal
stopSTT --> listenEnd
listenEnd --> startWW
```
Operation flow.
1. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
2. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
3. If processing does not detect a wake word, continue at step 1.
4. Invoke [0.^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) for the wake word.
5. Invoke [^listen-begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-begin) and start VAD processing.
6. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
7. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
8. If VAD processing does not detect the start of speech within the [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence) timeout, invoke [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence) and continue at step 15.
9. Invoke [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin) if processing detects the start of speech, else continue at step 6.
10. Read audio date from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
11. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
12. If VAD processing detects an endpoint invoke either [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit) or [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end) and continue at step 14.
13. Process VAD segmented audio in the LVCSR or STT recognizer
* Invoke [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) with interim recognition result hypothesis.
* Continue at step 10.
14. Produce a final LVCSR or STT recognition hypothesis.
* Invoke [^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) for each NLU intent found.
* Invoke [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) with the final recognition hypothesis.
* If there's no SLM, continue at step 15.
* Invoke [^slm-start](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-start), if the callback returns [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop), continue at step 15.
* Generate SLM result, invoking [^slm-result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result-partial) on each generated token.
* Invoke [^slm-result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result) with complete SLM result.
15. Invoke [^listen-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-end) and start listening for the wake word again at step 1.
Register callback handlers with [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) only for those events you're interested in.
## Settings
**Available 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), [^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), [^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), [^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), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event), [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence), [^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-start](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-start)
**Available iterators:** [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator), [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator)
**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)
**Available runtime settings:** [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), [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)
**Available configuration settings:** [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [backlog-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backlog-interval), [backoff](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backoff), [custom-vocab](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#custom-vocab), [delay](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#delay), [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms), [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), [include-wake-word-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-wake-word-audio), [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence), [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point), [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording), [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point), [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval), [samples-per-second](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#samples-per-second), [stt-profile](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#stt-profile), [sv-threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#sv-threshold), [wake-word-at-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#wake-word-at-end)
**Available values:** [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)
**Also see these related items:** [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spot-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code), [PhraseSpot.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-code)
## Notes
Use this template for command and control type applications where commands are
initiated with a wake word.
The [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) and [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) events are for the LVCSR or STT recognizer
in slot 1. If you need direct access to the wake word result, prefix the event
with the slot path: `0.^result` Use the slot prefix to read values in the `0.^result` event handler too, for example call [getString](https://doc.sensory.com/tnl/7.8/api/inference.md#getters) with key [0.text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) to read the wake word transcription.
Set [include-wake-word-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-wake-word-audio)` = 1` to include the wake word audio in the
samples passed to the LVCSR or STT recognizer. STT hypotheses do not include the wake word
text unless Sensory specifically configured the model to do so.
## Examples
```console
% cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9
% bin/snsr-edit -o vg-stt.snsr\
-t model/tpl-spot-vad-lvcsr-3.23.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
# Say "Voice genie, open the sunroof."
% snsr-eval -vt vg-stt.snsr
Using live audio from default capture device. ^C to stop.
P 2770 3250 (0.4166) Open the sun
P 2810 3650 (0.7161) Open the sunroof
1815 3990 [^end] VAD speech region.
NLU intent: open_window (0.9956) = open the sunroof
NLU entity: roof (0.9595) = sunroof
2810 3690 (0.4394) Open the sunroof.
^C
```
*[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
*[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/tpl/tpl-spot-vad.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/tpl/tpl-spot-vad/"
---
# tpl-spot-vad
This [template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) runs the [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0)
until it detects, then does start- and endpoint detection with a [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type)
on the audio stream following the wake word.
`tpl-spot-vad` has [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type)` == `[phrasespot-vad](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot-vad).
Expected [task types](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type):
* **Slot 0:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
**Also see these related items:** [tpl-spot-vad-3.13.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-spot-vad)
## Operation
```mermaid
flowchart TD
start((start))
start --> startWW
subgraph slot0[slot 0 (phrasespot)]
startWW((start))
fetchWW[/samples from ->audio-pcm/]
audioWW(^sample-count)
processWW[process]
result(^result)
stopWW((stop))
startWW --> fetchWW
fetchWW --> audioWW
audioWW --> processWW
processWW --> fetchWW
processWW -->|recognize| result
result --> stopWW
end
listenBegin(^listen-begin)
listenEnd(^listen-end)
stopWW --> listenBegin
listenBegin --> fetch0
fetch0[/samples from ->audio-pcm/]
fetch1[/samples from ->audio-pcm/]
audio0(^sample-count)
audio1(^sample-count)
silence(^silence)
begin(^begin)
END(^end)
limit(^limit)
process0[process]
process1[process]
out[\samples to <-audio-pcm\]
final@{ shape: f-circ }
fetch0 --> audio0
audio0 --> process0
process0 --> fetch0
process0 -->|speech start| begin
process0 -->|timeout| silence
silence --> final
begin --> fetch1
fetch1 --> audio1
audio1 --> out
out --> process1
process1 --> fetch1
process1 -->|speech end| END
process1 -->|speech limit| limit
END --> final
limit --> final
final --> listenEnd
listenEnd --> startWW
```
Operation flow.
1. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
2. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
3. If processing detects a vocabulary phrase, skip to step 5.
4. Continue processing until [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end) occurs on [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm),
or one of the event handlers returns a code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok).
5. Invoke [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result)
6. Invoke [^listen-begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-begin)
7. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
8. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
9. If speech detected within [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence) ms continue at step 12.
10. If _no_ speech detected within [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence) ms, invoke [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence)
and skip to step 19.
11. Continue processing at step 7 until [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end).
12. Invoke [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin).
13. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
14. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
15. If [pass-through](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#pass-through) `== 1` write speech samples to [<-audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-pcm-out).
16. If end detected within [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording) ms, invoke [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end)
and skip to step 19.
17. If end _not_ detected within [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording) ms, invoke [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit)
and skip to step 19.
18. Continue processing at step 13 until [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end).
19. Invoke [^listen-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#listen-end)
20. Restart at step 1.
Register callback handlers with [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) only for those events you're interested in.
## Settings
**Available 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), [^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), [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event), [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence)
**Available iterators:** [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator), [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator)
**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)
**Available runtime settings:** [->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), [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), [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), [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)
**Available configuration settings:** [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [backoff](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backoff), [delay](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#delay), [dsp-target](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-target), [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms), [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), [include-wake-word-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-wake-word-audio), [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence), [listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window), [low-fr-operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#low-fr-operating-point), [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording), [operating-point](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#operating-point), [pass-through](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#pass-through), [samples-per-second](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#samples-per-second), [sv-threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#sv-threshold), [wake-word-at-end](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#wake-word-at-end)
**Available values:** [phrasespot-vad](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot-vad)
**Also see these related items:** [live-segment.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-segment.md#live-segment-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code), [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudio-code)
## Notes
Use this for wake-word gated audio sent to cloud engines.
Set [include-wake-word-audio](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#include-wake-word-audio) `= 1` to include the wake word audio in the
VAD audio output stream.
This template writes the VAD-segmented audio to [<-audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-pcm-out).
If your application does not use this, set [pass-through](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#pass-through) `= 0`.
## Examples
```console
% cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9
% bin/snsr-edit -o vg-vad.snsr\
-t model/tpl-spot-vad-3.13.0.snsr\
-f 0 model/spot-voicegenie-enUS-6.5.1-m.snsr\
-s include-wake-word-audio=1
# Say "Voice genie, what's the capital of Oregon?"
% bin/snsr-eval -o vad-audio.wav -vvt vg-vad.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:
1950 2550 (1) voicegenie
words:
1950 2550 (1) voicegenie
2730 [^listen-begin]
2730 [^begin]
1650 4200 [^end] VAD speech region.
4980 [^listen-end]
^C
```
Review _vad-audio.wav_ and note that the recording starts [backoff](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backoff) ms before the
the beginning of "voice genie" and continues until [hold-over](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#hold-over) ms after the end
of the utterance.
*[API]: Application Programming Interface
*[FR]: False Reject: the recognizer did not trigger when the target phrase was spoken
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
*[VAD]: Voice Activity Detector
---
source_path: "models/tpl/tpl-vad-lvcsr.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/tpl/tpl-vad-lvcsr/"
---
# tpl-vad-lvcsr _(tnl)_
This [template](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) detects speech with a [VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type)
and sends the segmented audio to the [LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type) or [STT](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type)
recognizer in slot [0](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#0).
`tpl-vad-lvcsr` has [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).
Expected [task types](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type):
* **Slot 0:** [lvcsr](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#lvcsr)
**Also see these related items:** [tpl-vad-lvcsr-3.17.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-vad-lvcsr), [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)
## Operation
```mermaid
flowchart TD
start((start))
start --> fetch0
subgraph slot0[slot 0 (lvcsr)]
startSTT((start))
startSTTfinal((start))
stopSTT((stop))
stopSTTpartial((stop))
processSTT[process]
partialSTT(^result-partial)
intentSTT(^nlu-intent)
slotSTT(^nlu-slot)
resultSTT(^result)
nluSTT{NLU match?}
slmSTT{SLM included?}
generateSTT[generate]
slmstartSTT(^slm-start)
slmresultpartialSTT(^slm-result-partial)
slmresultSTT(^slm-result)
startSTT --> processSTT
processSTT ---->|hypothesis| partialSTT
partialSTT --> stopSTTpartial
startSTTfinal --> nluSTT
nluSTT -->|yes| intentSTT
nluSTT -->|no| resultSTT
intentSTT --> slotSTT
slotSTT --> resultSTT
slotSTT -->|more| intentSTT
resultSTT --> slmSTT
slmSTT -->|yes| slmstartSTT
slmSTT -->|no| stopSTT
slmstartSTT -->|OK| generateSTT
slmstartSTT -->|STOP| stopSTT
generateSTT -->|response| slmresultpartialSTT
slmresultpartialSTT --> generateSTT
generateSTT -->|done| slmresultSTT
slmresultSTT --> stopSTT
end
fetch0[/samples from ->audio-pcm/]
fetch1[/samples from ->audio-pcm/]
audio0(^sample-count)
audio1(^sample-count)
silence(^silence)
begin(^begin)
END(^end)
limit(^limit)
process0[VAD process]
process1[VAD process]
final@{ shape: f-circ }
listenEnd@{ shape: f-circ }
fetch0 --> audio0
audio0 --> process0
process0 --> fetch0
process0 -->|speech start| begin
process0 -->|timeout| silence
silence ~~~ final
silence --> listenEnd
begin --> fetch1
fetch1 --> audio1
audio1 --> process1
process1 --> startSTT
stopSTTpartial --> fetch1
process1 -->|speech end| END
process1 -->|speech limit| limit
END --> final
limit --> final
final --> startSTTfinal
stopSTT --> listenEnd
listenEnd ----> fetch0
```
Operation flow.
1. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
2. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
3. If VAD processing does not detect the start of speech within the [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence) timeout, invoke [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence) and continue at step 1.
4. Invoke [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin) if processing detects the start of speech, else continue at step 1.
5. Read audio date from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
6. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
7. If VAD processing detects an endpoint invoke either [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit) or [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end) and continue at step 9.
8. Process VAD segmented audio in the LVCSR or STT recognizer
* Invoke [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) with interim recognition result hypothesis.
* Continue at step 5.
9. Produce a final LVCSR or STT recognition hypothesis.
* Invoke [^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) for each NLU intent found.
* Invoke [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) with the final recognition hypothesis.
* If there's no SLM, continue at step 1.
* Invoke [^slm-start](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-start), if the callback returns [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop), continue at step 1.
* Generate SLM result, invoking [^slm-result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result-partial) on each generated token.
* Invoke [^slm-result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result) with complete SLM result.
* Continue at step 1.
Register callback handlers with [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) only for those events you're interested in.
## Settings
**Available 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), [^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), [^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), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event), [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence), [^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-start](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-start)
**Available iterators:** _none_
**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)
**Available runtime settings:** [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), [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)
**Available configuration settings:** [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [backoff](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#backoff), [custom-vocab](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#custom-vocab), [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), [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording), [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval), [samples-per-second](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#samples-per-second), [stt-profile](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#stt-profile)
**Available values:** [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)
**Also see these related items:** [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spot-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code), [PhraseSpot.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-code)
## Notes
Use this template for command and control type applications where commands are initiated
just by speaking.
## Examples
```console
% cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9
% bin/snsr-edit -o vad-stt.snsr\
-t model/tpl-vad-lvcsr-3.17.0.snsr\
-f 0 model/stt-enUS-automotive-medium-2.3.15-pnc.snsr
# Say, for example: "Turn the air conditioning up all the way"
% snsr-eval -t vad-stt.snsr
P 1000 1040 T
P 1000 1600 Turn the egg
P 1040 2040 Turn the air conditioner
P 1040 2320 Turn the air conditioning up
P 1040 2760 Turn the air conditioning up all the way
NLU intent: set_fan (0.9547) = turn the air conditioning up 100%
NLU entity: hvac (0.9744) = air conditioning
NLU entity: percentage_value (0.8963) = 100%
1040 2880 Turn the air conditioning up all the way.
^C
```
*[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
*[VAD]: Voice Activity Detector
---
source_path: "models/types/ca.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/types/ca/"
---
# Adapting wake word
These are fixed wake word models that continuously
adapt to speakers' voices to improve false-accept rates.
They are drop-in replacements for fixed wake words.
Continuously adapting wake word models 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 filenames that by convention match `ca-*.snsr`
**Also see these related items:** [Adapting wake word models](https://doc.sensory.com/tnl/7.8/models/index.md#ca-models) included in this distribution.
## Operation
```mermaid
flowchart TD
start((start))
fetch[/samples from ->audio-pcm/]
audio(^sample-count)
process
result(^result)
adaptStarted(^adapt-started)
adapted(^adapted)
newUser(^new-user)
start --> fetch
fetch --> audio
audio --> process
process --> fetch
process -->|recognize| result
process -->|recognize w/ high SNR| adaptStarted
adaptStarted --> result
result --> fetch
fetch -->|adapted| adapted
adapted --> fetch
adapted -->|new user identified| newUser
newUser --> fetch
```
Recognition flow.
1. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
2. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
3. Invoke [^adapt-started](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapt-started) if processing detects a vocabulary phrase in a low-noise environment. This starts adapting the model to the speaker's voice on a background thread.
4. Invoke [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) if processing detects a vocabulary phrase.
5. Invoke [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted) when the background thread has finished adding an enrollment.
* Invoke [^new-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#new-user) if adaptation detects a user it hasn't seen before.
6. Continue processing until [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end) occurs on [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm),
or one of the event handlers returns a code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok).
Register callback handlers with [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) only for those events you're interested in.
## Settings
**Available events:** [^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), [^new-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#new-user), [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event)
**Available iterators:** [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator), [user-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#user-iterator), [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator)
**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)
**Available runtime settings:** [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), [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), [delete-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#delete-user), [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), [rename-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#rename-user)
**Available configuration settings:** [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [cache-file](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#cache-file), [delay](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#delay), [dsp-target](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-target), [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms), [listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window), [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), [samples-per-second](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#samples-per-second), [sv-threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#sv-threshold)
**Available values:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
**Also see these related items:** [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spot-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code), [PhraseSpot.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-code), [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudio-code)
*[API]: Application Programming Interface
*[FR]: False Reject: the recognizer did not trigger when the target phrase was spoken
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
---
source_path: "models/types/enroll.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/types/enroll/"
---
# Wake word enrollment
These models provide user enrollment for EFT and UDT. They produce [wake-word models](https://doc.sensory.com/tnl/7.8/models/index.md#wake-word-models).
Enrollment models have [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type)` == `[enroll](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#enroll)
and filenames that by convention match `eft-*.snsr` or `udt-*.snsr`
**Also see these related items:** [wake word enrollment models](https://doc.sensory.com/tnl/7.8/models/index.md#enroll-models) included in this distribution.
## Operation
Wake word enrollment has two modes: [interactive](https://doc.sensory.com/tnl/7.8/models/types/enroll.md#enroll-interactive)
for live recordings, and [offline](https://doc.sensory.com/tnl/7.8/models/types/enroll.md#enroll-offline) for pre-recorded
enrollment audio.
### Interactive
With [interactive](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#interactive) `= 1` enrollment tasks expect live audio and re-record enrollments
that cannot be used.
```mermaid
flowchart TD
start((start))
fetch[/samples from ->audio-pcm/]
audio(^sample-count)
segment[segment audio]
check[check audio quality]
validate[check enrollment consistency]
resume(^resume)
next(^next)
pause(^pause)
pass(^pass)
fail0(^fail)
fail1(^fail)
enrolled(^enrolled)
progress(^progress)
adapted(^adapted)
done(^done)
zeroCount[count←0]
incrCount[count++]
start --> next
next --> zeroCount
zeroCount --> resume
resume --> fetch
fetch --> audio
audio --> segment
segment --> fetch
segment -->|endpoint| pause
pause --> check
check -->|good| pass
pass ---> incrCount
incrCount --> resume
pass -->|count == required| validate
validate -->|good| next
validate -->|bad| fail1
check -->|bad| fail0
fail0 --> resume
fail1 --> zeroCount
next -->|user == NULL| enrolled
enrolled --> enroll
enroll --> progress
progress --> enroll
enroll --->|complete| adapted
adapted --> done
done ~~~ validate
```
Interactive enrollment flow.
1. Invoke [^next](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#next).
* If the callback set [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) to `NULL`, start model adaptation at step 8.
2. Reset the enrollment `count` to `0`. This tracks the number of usable enrollments
for the current user or phrase.
3. Invoke [^resume](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#resume). Application should use this to restart audio recording.
4. Make an audio recording and segment it with a VAD (UDT) or a wake word (EFT).
* Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
* Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
* Process and repeat until a speech segment is found.
5. Invoke [^pause](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#pause). Application should pause audio recording.
6. Check enrollment audio quality.
* If good, invoke [^pass](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#pass).
If we have [req-enroll](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#req-enroll) enrollments, start validation at step 7,
else start the next recording at step 3.
* If bad, invoke [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail) and redo the current recording at step 3.
7. Validate all the enrollment recordings, checking for consistency.
* If good, start enrolling the next user or phrase at step 1.
* If bad, invoke [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail) and restart at step 2.
8. When all users / phrases are available, invoke [^enrolled](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#enrolled).
9. Train a new recognizer with the enrollments
* Call [^progress](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#progress) repeatedly until done.
10. Invoke [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted).
11. Invoke [^done](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#done).
**Also see these related items:** [live-enroll.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-enroll.md#live-enroll-code), [enrollUDT.java](https://doc.sensory.com/tnl/7.8/api/sample/java/enrollUDT.md#enrolludt-code), [Enroll.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-enroll)
### Offline
With [interactive](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#interactive) `= 0` enrollment tasks expect pre-recorded audio and fails
if any of the enrollments cannot be used.
```mermaid
flowchart TD
start((start))
fetch[/samples from ->audio-pcm/]
audio(^sample-count)
segment[segment audio]
check[check audio quality]
validate[check enrollment consistency]
next(^next)
pass(^pass)
fail0(^fail)
fail1(^fail)
enrolled(^enrolled)
progress(^progress)
adapted(^adapted)
done(^done)
skip[discard enrollment]
skipBad[discard bad enrollment]
zeroCount[count←0]
incrCount[count++]
user0{user == NULL?}
user1{user == NULL?}
start --> user0
user0 -->|yes| next
user0 -->|no| user1
next --> user1
user1 -->|no| zeroCount
zeroCount --> fetch
fetch --> audio
audio --> segment
segment --> fetch
segment -->|endpoint| check
check --->|good| pass
pass --> incrCount
incrCount --> fetch
validate --->|bad| fail1
fail1 --> skipBad
skipBad --> validate
validate --> user1
check -->|bad| fail0
fail0 --> skip
skip --> fetch
fetch -->|STREAM_END| validate
user1 ---->|yes| enrolled
enrolled --> enroll
enroll --> progress
progress --> enroll
enroll --->|complete| adapted
adapted --> done
```
Offline enrollment flow.
1. If [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) `== NULL`, invoke [^next](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#next). The application should set [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) before
starting enrollment, or do so in the [^next](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#next) callback.
2. If [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user) `== NULL`, start model adaptation at step 7.
3. Reset the enrollment `count` to `0`. This tracks the number of usable enrollments
for the current user or phrase.
4. Segment audio with a VAD (UDT) or a wake word (EFT).
* Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
* Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
* Process and repeat until a speech segment is found or [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end).
* If [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end), validate at step 6.
5. Check enrollment audio quality.
* If good, invoke [^pass](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#pass) and keep the recording.
* If bad, invoke [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail) and discard the recording.
* Start the next recording at step 4.
6. Validate all the enrollment recordings, checking for consistency.
* If no bad recordings remain, start enrolling the next user or phrase at step 2.
* If bad, invoke [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail), remove the recording and revalidate.
7. When all users / phrases are available, invoke [^enrolled](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#enrolled).
8. Train a new recognizer with the enrollments
* Call [^progress](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#progress) repeatedly until done.
9. Invoke [^adapted](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#adapted).
10. Invoke [^done](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#done).
**Also see these related items:** [spot-enroll.c](https://doc.sensory.com/tnl/7.8/api/sample/c/spot-enroll.md#spot-enroll-code)
## Settings
**Available events:** [^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), [^fail](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#fail), [^next](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#next), [^pass](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#pass), [^pause](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#pause), [^progress](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#progress), [^resume](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#resume), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event)
**Available 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), [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator)
**Available results:** _none_
**Available runtime settings:** [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), [add-context](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#add-context), [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), [delete-user](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#delete-user), [re-adapt](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#re-adapt), [user](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#user)
**Available configuration settings:** [accuracy](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#accuracy), [enrollment-task-index](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#enrollment-task-index), [interactive](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#interactive), [req-enroll](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#req-enroll)
**Available values:** [enroll](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#enroll)
**Also see these related items:** [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spot-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code)
*[API]: Application Programming Interface
*[EFT]: Enrolled Fixed Trigger: fixed wake words adapted to a speaker to improve accuracy
*[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: "models/types/index.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/types/"
---
# Model types
The [type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type) of a model specifies the runtime behavior: what it does, which [setting keys](https://doc.sensory.com/tnl/7.8/api/setting-keys/index.md#setting-keys) it supports, and when it invokes [event](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#events) callbacks.
These SDKs support both [fundamental](https://doc.sensory.com/tnl/7.8/models/types/index.md#fundamental-models) and [composed](https://doc.sensory.com/tnl/7.8/models/types/index.md#composed-models) model types. Fundamental types include wake words, adapting wake words, models that create wake words through user enrollment, VAD, LVCSR, and STT. Templates add features by composition, combining multiple fundamental models into one.
The TrulyHandsfree SDK supports all wake word, wake word enrollment, and VAD models.
TrulyNatural (Lite) includes TrulyHandsfree and support for LVCSR. TrulyNatural STT includes TrulyNatural (Lite) and adds speech to text.
## Fundamental models
[Wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type)
- Fixed and enrolled wake words, and keyword spotted command sets.
[Adapting wake word](https://doc.sensory.com/tnl/7.8/models/types/ca.md#ca-type)
- Fixed wake word models that continuously adapt to speakers' voices to improve false-accept rates.
[Wake word enrollment](https://doc.sensory.com/tnl/7.8/models/types/enroll.md#enroll-type)
- Adapts fixed (EFT) and user-defined (UDT) wake words to speakers' voices, creating [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type) models specific to these speakers.
[VAD](https://doc.sensory.com/tnl/7.8/models/types/vad.md#vad-type)
- Finds the start- and endpoints of speech segments in a stream of audio data.
[LVCSR](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#lvcsr-type) _(tnl)_
- These recognizers use a phonetic acoustic model and an FST vocabulary decoder. They are suitable for small to medium vocabulary tasks, but not for audio transcription
[STT](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type) _(stt)_
- Audio transcription with transformers.
## Composed models
[Templates](https://doc.sensory.com/tnl/7.8/models/tpl/index.md#template-type) add behavior to the fundamental model types listed above. Use these, for example, to create a single model that waits for a keyword, runs a VAD, and then recognizes the segmented speech with an STT recognizer. This composed model uses the same API as a simple wake word and does not require application code changes.
*[API]: Application Programming Interface
*[EFT]: Enrolled Fixed Trigger: fixed wake words adapted to a speaker to improve accuracy
*[FST]: Finite-State Transducer
*[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
*[VAD]: Voice Activity Detector
---
source_path: "models/types/lvcsr.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/types/lvcsr/"
---
# LVCSR _(tnl)_
These recognizers use a phonetic acoustic model and an FST vocabulary decoder.
They are suitable for small to medium vocabulary tasks, but not for
unconstrained audio transcription.
These models have [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) and filenames that
by convention match `lvcsr-*.snsr`
You can create LVCSR recognizers with [VoiceHub](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub) or by
[specifying a grammar](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) with build-capable[^1] model.
LVCSR recognizers include support for decoding with statistical [language models],
but Sensory does not distribute the tools we use to create these[^2]. Language models can
provide improved accuracy for constrained target domains. _For transcription type
tasks we recommend that you use an STT model instead._
Our FST decoder supports hybrid models that contain both grammar-based and language model components.
**Also see these related items:** [LVCSR models](https://doc.sensory.com/tnl/7.8/models/index.md#lvcsr-models) included in this distribution.
[^1]: LVCSR models created by [VoiceHub](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub) include build components only if the grammar references
at least one user-defined class, such as `~dynamic-1`. If the grammar contains no unresolved classes
VoiceHub removes the build components to reduce model files size and RAM use.
[^2]: Contact your [sales representative](https://doc.sensory.com/tnl/7.8/contact.md#sales) if you would like to explore using a custom language model
for your application.
## Operation
```mermaid
flowchart TD
start((start))
fetch[/samples from ->audio-pcm/]
audio(^sample-count)
process
partial(^result-partial)
intent(^nlu-intent)
slot(^nlu-slot)
result(^result)
nlu{NLU match?}
start --> fetch
fetch --> audio
audio --> process
process --> fetch
process -->|hypothesis| partial
partial --> fetch
process -->|VAD endpoint or STREAM_END| nlu
nlu -->|yes| intent
nlu -->|no| result
intent --> slot
slot --> result
slot -->|more| intent
result --> fetch
```
Recognition flow.
1. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
2. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
3. Invoke [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) with interim recognition hypotheses
every [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval) ms.
5. Continue processing until [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end) occurs on [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm),
one of the event handlers returns a code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok), or
an external [VAD](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#vad) detects a speech endpoint.
6. If NLU is configured, invoke [^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) for each
top-level result that matches.
7. Invoke [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) with the final recognition hypothesis.
8. Resume processing from step 1.
**Note:**
LVCSR recognizers do **not** produce a final recognition hypothesis until they
run out of audio samples to process, or an external VAD detects a speech
endpoint.
With live audio you should use these with a VAD template such as
[tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-vad-lvcsr), [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).
## Settings
**Available 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), [^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), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event)
**Available iterators:** _none_
**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)
**Available runtime settings:** [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), [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), [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream), [phrases-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#phrases-stream)
**Available configuration settings:** [ac-prune-top-k](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#ac-prune-top-k), [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [complete-only](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#complete-only), [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval), [ram-limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#ram-limit), [samples-per-second](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#samples-per-second), [search.frame-nota](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#searchframe-nota), [show-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#show-silence)
**Available values:** [lvcsr](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#lvcsr)
**Also see these related items:** [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spot-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code), [PhraseSpot.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-code), [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudio-code)
## Notes
Sensory optimizes hybrid models with a background component only to detect speech that is not in
the specified grammar. These models report an [nlu-intent-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-name) of `background` when they detect
out-of-grammar utterances. You should not use the out-of-grammar recognition [text](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#text) result
as this will have a high word error rate. Consider using [STT](https://doc.sensory.com/tnl/7.8/models/types/stt.md#stt-type) for transcription tasks instead.
[phrases-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#phrases-stream) provides a convenient way to specify a recognition vocabulary from an exhaustive
list of alternative utterances.
## Grammar-based recognition _(since [6.7.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.7.0))_
Sensory's LVCSR models use [grammars](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-syntax) to constrain the possible utterances
they can recognize. Focussing on a limited set of words and structures defined in these grammars
improves recognition speed and accuracy at the expense of recognizing arbitrary input.
You can create a custom recognizer by specifying a fixed grammar during development if
the recognition vocabulary is entirely known, or at runtime if it is not. You can also
use a hybrid approach and build the invariant parts during development, and delay
adding [variable parts](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-classes) (such as a list of favorite TV channels) until runtime.
### Creating a recognizer
Let's create a grammar-based recognizer using the [command-line tools](https://doc.sensory.com/tnl/7.8/tools/index.md#command-line-tools).
We'll use _data/grammars/enrollments.txt_ which contains a sample grammar specification for
the enrollment recordings in _data/enrollments/_.
We can create a custom recognizer using this grammar with [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit)
by specifying an LVCSR model that supports building and [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream).
### Details: _data/grammars/enrollments.txt_
```
# LVCSR grammar specification for test utterances in data/enrollments/
#
# In a tpl-spot-vad-lvcsr pipeline the prefix would be consumed by the spotter.
prefix = armadillo | jackalope | terminator;
# List of known utterances in the *-c.wav files.
sentence =
18 percent of 643 |
call the nearest target |
how far away is winco |
play more songs by this artist |
record a video |
start a timer for 20 minutes |
i'm running low on gas |
cancel all my meetings on friday |
directions to susan's house |
do i have any new texts |
open my calendar to next week |
set an alarm for 6 am tomorrow;
# 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 $sentence? ;
```
```console
% cd $HOME/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9
% bin/snsr-edit -vv -t model/lvcsr-build-enUS-12.13.1-5MB.snsr \
-f grammar-stream data/grammars/enrollments.txt \
-o lvcsr-enrollments.snsr
Loading "model/lvcsr-build-enUS-12.13.1-5MB.snsr" as the template model.
Loading "data/grammars/enrollments.txt" into setting "grammar-stream".
Saved edited model to "lvcsr-enrollments.snsr".
```
Run the new model with [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval):
```console
% bin/snsr-eval -t lvcsr-enrollments.snsr \
-s partial-result-interval=0 \ # (1)!
data/enrollments/armadillo-1-3-c.wav
165 2760 armadillo play more songs by this artist
```
1. We're setting [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval)` = 0` to see only the final recognition hypothesis.
For small grammars such as this the build time is negligible. We could
use [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval) to build and run the recognizer in a single operation:
```console
% bin/snsr-eval -t model/lvcsr-build-enUS-12.13.1-5MB.snsr \
-f grammar-stream data/grammars/enrollments.txt \
-s partial-result-interval=0 \
data/enrollments/armadillo-1-3-c.wav
165 2760 armadillo play more songs by this artist
```
### Classes
A symbol that starts with the tilde `~` sigil specifies a [recognition class](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-syntax-class).
Class recognizers have their own grammar specifications, separate from the top-level
grammar. The behavior of a class-based recognizer is similar to that specified
by a rule. Classes, however, can be updated without recompiling the rest of the grammar,
and all references to a class use the same recognizer. This can reduce the recognizer size
and improve build speed.
This example uses a modified enrollment grammar which references two toy
classes: `~number` and `~place`:
**`enrollments-class.txt`**
```
# LVCSR grammar specification for test utterances in data/enrollments/
# This references two class sub-recognizers: ~number and ~place
#
# In a tpl-spot-vad-lvcsr pipeline the prefix would be consumed by the spotter.
prefix = armadillo | jackalope | terminator;
# List of known utterances in the *-c.wav files.
sentence =
~number percent of ~number |
call the nearest ~place |
how far away is ~place |
play more songs by this artist |
record a video |
start a timer for ~number minutes |
i'm running low on gas |
cancel all my meetings on friday |
directions to ~place |
do i have any new texts |
open my calendar to next week |
set an alarm for ~number am tomorrow;
# 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 $sentence? ;
```
**`place.txt`**
```
# Example place name class recognizer.
g = target | winco | susan's house;
```
The `~number` and `~place` classes referenced in _enrollments-class.txt_
create two new dynamic settings for these classes: `grammar-stream.number` and
`grammar-stream.place`. Specify these to create a complete recognizer:
```console
% snsr-edit -v -t model/lvcsr-build-enUS-12.13.1-5MB.snsr\
-f grammar-stream enrollments-class.txt \
-g grammar-stream.number "g = 18 | 643 | 20 | 6;" \ # (1)!
-o lvcsr-enrollments-class.snsr
Output written to "lvcsr-enrollments-class.snsr".
```
1. [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit)'s `-g` option sets the [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream)`.number` stream to a string argument. We could have also used a file for the number grammar.
Run the recognizer:
```console
% snsr-eval -v -t lvcsr-enrollments-class.snsr \
-s partial-result-interval=0 \
data/enrollments/armadillo-1-0-c.wav
375 3195 (7.451e-09) armadillo 18 percent of 643
```
### Class libraries _(since [6.15.0](https://doc.sensory.com/tnl/7.8/changes/version-6.md#v6.15.0))_
TrulyNatural 6.15.0 introduced support for pre-built binary class repositories.
These contain classes built from frequently used grammar fragments such as dates, times, and numbers.
Load binary class repositories into the same [Session](https://doc.sensory.com/tnl/7.8/api/inference.md#session) as an LVCSR model to add this capability to the model. If a grammar references a class that's not explicitly defined, the class name is looked up in the provided class library or libraries. System class libraries provided by Sensory use a prefix of `s.` for all class names.
See [lvcsr-lib-enUS-1.2.0.snsr](https://doc.sensory.com/tnl/7.8/models/index.md#lvcsr-lib-enUS) for a description of the classes used below.
**`class-lib.txt`**
```
# Example recognizer with classes from a class library
call = call {number ~s.phone-number};
emergency = ~s.call-emergency;
timer = {timer ~s.timer-phrases};
commands = {call} | {emergency} | $timer;
g = $commands ;
```
We'll use live audio for this example, so we need to use [snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval)'s `-a` flag
to add a [VAD](https://doc.sensory.com/tnl/7.8/models/tpl/tpl-vad-lvcsr.md#tpl-vad-lvcsr-type) to find the end of each utterance and signal
the recognizer to produce a final hypothesis.
```console
% snsr-eval -a -t model/lvcsr-build-enUS-12.13.1-5MB.snsr \
-t model/lvcsr-lib-enUS-1.2.0.snsr \
-f grammar-stream class-lib.txt \
-s partial-result-interval=0
# Say: Call 800 555 1212
NLU intent: call (0) = call eight hundred five five five one two one two
NLU entity: number (0) = eight hundred five five five one two one two
7815 11190 call eight hundred five five five one two one two
# Say: Set a timer for 31 minutes.
NLU intent: timer (0) = set a timer for thirty one minutes
24375 27015 set a timer for thirty one minutes
# Say: Call the fire department.
NLU intent: emergency (0) = call the fire department
40110 41595 call the fire department
```
**C/C++**
Configuring class-based recognition with the C API:
```c
SnsrSession s;
snsrNew(&s);
snsrLoad(s, snsrStreamFromFileName("model/tpl-vad-lvcsr-3.17.0.snsr", "r"));
snsrSetStream(s, SNSR_SLOT_0,
snsrStreamFromFileName("model/lvcsr-build-enUS-12.13.1-5MB.snsr", "r"));
snsrLoad(s, snsrStreamFromFileName("model/lvcsr-lib-enUS-1.2.0.snsr", "r"));
snsrSetStream(s, SNSR_GRAMMAR_STREAM,
snsrStreamFromFileName("class-lib.txt", "r"));
if (snsrRC(s) != SNSR_RC_OK) {
fprintf(stderr, "ERROR: %s\n", snsrErrorDetail(s));
return snsrRC(s);
}
```
**Java**
Configuring class-based recognition with the Java API:
```java
SnsrSession s = new SnsrSession();
try {
s.load(SnsrStream.fromFileName("model/tpl-vad-lvcsr-3.17.0.snsr", "r"));
s.setStream(Snsr.SLOT_0,
SnsrStream.fromFileName("model/lvcsr-build-enUS-12.13.1-5MB.snsr", "r"));
s.load(SnsrStream.fromFileName("model/lvcsr-lib-enUS-1.2.0.snsr", "r"));
s.setStream(Snsr.GRAMMAR_STREAM,
SnsrStream.fromFileName("class-lib.txt", "r"));
} catch (IOException e) {
e.printStackTrace();
return s.rC();
}
```
### Syntax
A [context-free grammar] is a set of rules that describes the sequences
of words that an LVCSR model can recognize.
#### Definition
1. Grammars use [UTF-8][] encoding.
1. `#` marks the start of a comment, which extends to the end of the line.
1. A _grammar_ is a series of _rules_ representing variable definitions.
The final rule in a grammar specifies the recognition vocabulary and typically
references rules defined earlier. It should include the sentence start (``)
and end (` `) markers.
1. A _rule_ is an assignment of the form `name = expr ;` where
`name` is a _symbol_ and `expr` is a sequence of _symbols_ and _operators_.
`expr` is a type of [regular expression][].
1. A _symbol_ is a sequence of characters that does not include any whitespace
or operators, optionally prefixed by sigils `$` or `~`. A symbol without a
sigil is called a _terminal_ and is part of the recognition vocabulary,
for example `temperature`. [Special symbols](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-special) are predefined
terminals that describe input characteristics such as pauses and the edges of an utterance.
1. The `$` sigil does rule substitution _at build time_. The parser substitutes the
value of the rule named `name` for `$name`. Substitutions include
an implicit _grouping_ operator: Grammar `a = 1 | 2 | 3; b = $a ;`
is equivalent to `b = (1 | 2 | 3) ;`.
1. The `~` sigil substitutes a named recognition class _at runtime_.
- Each class is a recognizer with its own grammar, separate from the main grammar.
- All references to a class use instances of the same class recognizer.
- You can update each class in isolation, without having to recompile the main grammar.
- If you have a large rule that's referenced multiple times, converting it to a
class can speed up build time significantly.
- Use classes to augment a recognition vocabulary at runtime. In a voice dialing
application, for example, one would define the entire recognition grammar
at build time but use `~contacts` instead of a predefined list of contact names.
Once loaded, the application would scan the address book and build only the
`~contacts` class.
- Specify class definitions with [grammar-stream.classname](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream) or [phrases-stream.classname](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#phrases-stream), for example `phrases-stream.contacts`.
2. Operators include _grouping_ parentheses, brackets, and braces, _infix_ operators that indicate
logical AND and OR between symbols, and _postfix_ operators that change how the preceding symbol matches input.
The [operator precedence](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-op-precedence) table lists the order and direction in which the parser applies
operators.
3. Grouping
- `( )` Parentheses enclose items that are grouped together.
- `[ ]` Square brackets enclose optional items.
`[...]` is equivalent to `(...)?`.
- `{ }` Braces implement slot-capturing lightweight NLU markup.
- `{slotName a b c}` makes `a b c` available as the [nlu-slot-value](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-value) of
[nlu-slot-name](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-slot-name) `slotName` when the recognizer matches `a b c` to the input
audio.
- You can nest NLU slots to an arbitrary depth.
- We define the outermost slots as [intents](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-intent-name) and all the nested
slots in each intent as [entities](https://doc.sensory.com/tnl/7.8/api/setting-keys/results.md#nlu-entity-name).
- Each identified intent invokes handlers registered for [^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).
- `{rule}` is shorthand for `{rule $rule}`.
- With this grammar:
```
seconds = 1 | 2 | 4 | 8 | half:0.5 a:? | a:? quarter:0.25 [of: a:];
shutterSpeed = set shutter speed to {seconds} ( second | seconds );
cmd = {shutterSpeed} ;
```
an utterance of "set shutter speed to a quarter of a second" will produce
`set shutter speed to 0.25 second`
as recognition output,
with an additional [^nlu-intent](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#nlu-intent) callback for the top-level
`shutterSpeed` slot:
```
NLU intent: shutterSpeed (0) = set shutter speed to 0.25 second
NLU entity: seconds (0) = 0.25
```
4. Infix operators
- These are valid between symbols and may be surrounded by whitespace.
- `^` is the conjunction operator and is implied between adjacent terminals:
Grammar `g = one two three;` will recognize only the sequence "one two three".
- `|` is the disjunctive operator. It separates alternative items.
Grammar `g = one | two | three;` will recognize "one", or "two", or "three".
5. Postfix operators
- These directly follow a symbol without any intervening whitespace.
- `?` A question mark following a symbol makes that symbol optional:
It requires zero or one repetitions of the symbol.
- `+` A plus sign following a symbol or a group requires one or more repetitions of it.
- `*` An asterisk following a symbol or a group requires zero or more repetitions.
- `:` is the rewrite operator.
- `left:right` recognizes symbol `left` but produces terminal `right` as a recognition result.
- `left:` recognizes symbol `left` but rewrites that to an empty string, eliding
`left` from the recognition result.
- `:right` inserts `right` into the recognition result.
If you say "one two three", grammar
`g = one :mississippi two :mississippi three ;` produces
"one mississippi two mississippi three".
- `/` A forward slash following a symbol followed by a floating point number defines
a weight to be associated with that symbol. If there's a rewrite operator (`:`)
the slash must follow the rewritten-to terminal, for example: `one:een/0.123`
Weights are in the logprob domain, convert from a $[0, 1]$ probability to
a weight with $w = -log_{10}(p)$.
The default symbol weight is `0` for a probability of `1.0`.
6. `\` escape symbol. To include a literal special character in a grammar specification, escape it with a backslash. The list of characters that support this include:
`^`, `|`, `*`, `+`, `?`, `=`, `[ ]`, `( )`, `;`, `#`, and `:`.
**Also see these related items:** [grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#grammar-stream), [phrases-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#phrases-stream), [nlu-grammar-stream](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#nlu-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)
#### Operator precedence
The following table lists the precedence and associativity of grammar
operators. Operators are listed in descending precedence: level `0`
is applied first and level `5` last.
Precedence | Operator | Description | Associativity
:---------:|:--------:|-------------|--------------
0 | `:` | Rewrite output
0 | `/` | Symbol weight
1 | `( )` | Grouping
1 | `[ ]` | Optional group
1 | `{ }` | Slot-capturing semantic markup
2 | `?` | Zero-or-one symbol | left-to-right
2 | `+` | One-or-more symbols | left-to-right
2 | `*` | Zero-or-more symbols | left-to-right
3 | `^` | And, implied between symbols | right-to-left
4 | `|` | Alternative | right-to-left
5 | `=` | Rule assignment | right-to-left
This grammar:
```
a = one | two three four;
g = ( $a | five six) ;
```
will recognize only these phrases:
```
one
two three four
five six
```
#### Special symbols
A grammar can include these special symbols:
- `` - The silence at the start of a sentence.
- ` ` - The silence at the end of a sentence.
- `` - Short pauses between words. The grammar compiler automatically
adds these where needed, so there is no need to do so explicitly.
Do **not** add `` to NLU grammars, use ` ` instead.
- ` ` - A explicit short pause.
- ` ` - Matches when none of the alternatives are likely
(i.e. "none of the above").
+ Recognition results at the phrase level can include ` ` even
if this symbol was not explicitly used in the grammar. This is an
indication that the result was rejected due to [search.frame-nota](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#searchframe-nota), or that
RAM or CPU constraints limited the recognizer's ability to produce a result.
- ` ` - Similar to ` `. In *some* models the
threshold for determining whether this symbol matches better than any
other is different from that of ` `.
- `.` - When used with lightweight [NLU grammars](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#nlu-grammar-stream)
a single period matches any input word.
Use `.:*` to match any input words and remove them from the NLU result.
[regular expression]: https://en.wikipedia.org/wiki/Regular_expression
[UTF-8]: https://en.wikipedia.org/wiki/UTF-8
*[API]: Application Programming Interface
*[FST]: Finite-State Transducer
*[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
*[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/types/stt.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/types/stt/"
---
# Speech To Text _(stt)_
These models do audio transcription with transformers.
STT models have [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) and filenames that
by convention match `stt-*.snsr`
**Also see these related items:** [STT models](https://doc.sensory.com/tnl/7.8/models/index.md#stt-models) included in this distribution.
## Operation
```mermaid
flowchart TD
start((start))
fetch[/samples from ->audio-pcm/]
audio(^sample-count)
process[process]
partial(^result-partial)
intent(^nlu-intent)
slot(^nlu-slot)
result(^result)
nlu{NLU match?}
slm{SLM included?}
generate[generate]
slmstart(^slm-start)
slmresultpartial(^slm-result-partial)
slmresult(^slm-result)
start --> fetch
fetch --> audio
audio --> process
process --> fetch
process -->|hypothesis| partial
partial --> fetch
process -->|VAD endpoint or STREAM_END| nlu
nlu -->|yes| intent
nlu -->|no| result
intent --> slot
slot --> result
slot -->|more| intent
result --> slm
slm -->|yes| slmstart
slm -->|no| fetch
slmstart -->|OK| generate
slmstart -->|STOP| fetch
generate -->|response| slmresultpartial
slmresultpartial --> generate
generate -->|done| slmresult
slmresult --> fetch
```
Recognition flow.
1. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
2. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
3. Invoke [^result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result-partial) with interim recognition hypotheses
every [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval) ms.
5. Continue processing until [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end) occurs on [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm),
one of the event handlers returns a code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok), or
an external [VAD](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#vad) detects a speech endpoint.
6. If NLU is configured, invoke [^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) for each
top-level result that matches.
7. Invoke [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) with the final recognition hypothesis.
8. If an SLM is not available, resume processing at step 1.
9. Invoke [^slm-start](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-start). If the handler returns [STOP](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stop),
resume processing at step 1.
10. Invoke [^slm-result-partial](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result-partial) as the model generates text.
11. Invoke [^slm-result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-result) when text generation is complete.
12. Resume processing at step 1.
**Note:**
STT recognizers do **not** produce a final recognition hypothesis until they
run out of audio samples to process, or an external VAD detects a speech
endpoint.
With live audio you should use these with a VAD template such as
[tpl-vad-lvcsr](https://doc.sensory.com/tnl/7.8/models/index.md#tpl-vad-lvcsr), [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).
## Settings
**Available 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), [^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), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event), [^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-start](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#slm-start)
**Available iterators:** _none_
**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)
**Available runtime settings:** [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), [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)
**Available configuration settings:** [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [custom-vocab](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#custom-vocab), [partial-result-interval](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#partial-result-interval), [samples-per-second](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#samples-per-second), [stt-profile](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#stt-profile)
**Available values:** [lvcsr](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#lvcsr)
**Also see these related items:** [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spot-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code), [PhraseSpot.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-code), [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudio-code)
*[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
*[VAD]: Voice Activity Detector
---
source_path: "models/types/vad.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/types/vad/"
---
# VAD
Models of this type find speech segments in audio data streams.
Wake word models have [task-type](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#task-type)` == `[vad](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#vad) and filenames that
by convention match `vad-*.snsr`
**Also see these related items:** [VAD models](https://doc.sensory.com/tnl/7.8/models/index.md#vad-models) included in this distribution.
## Operation
```mermaid
flowchart TD
start((start))
fetch0[/samples from ->audio-pcm/]
fetch1[/samples from ->audio-pcm/]
audio0(^sample-count)
audio1(^sample-count)
silence(^silence)
begin(^begin)
END(^end)
limit(^limit)
process0[process]
process1[process]
out[\samples to <-audio-pcm\]
final@{ shape: f-circ }
start --> fetch0
fetch0 --> audio0
audio0 --> process0
process0 --> fetch0
process0 -->|speech start| begin
process0 -->|timeout| silence
silence --> final
begin --> fetch1
fetch1 --> audio1
audio1 --> out
out --> process1
process1 --> fetch1
process1 -->|speech end| END
process1 -->|speech limit| limit
END --> final
limit --> final
final --> fetch0
```
Endpointing flow.
1. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
2. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
3. If speech detected within [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence) ms continue at step 6.
4. If _no_ speech detected within [leading-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#leading-silence) ms, invoke [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence)
and restart from step 1.
5. Continue processing at step 1 until [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end).
6. Invoke [^begin](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#begin).
7. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
8. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
9. If [pass-through](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#pass-through) `== 1` write speech samples to [<-audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-pcm-out).
10. If end detected within [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording) ms, invoke [^end](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#end)
and restart from step 1.
11. If end _not_ detected within [max-recording](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#max-recording) ms, invoke [^limit](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#limit)
and restart from step 1.
12. Continue processing at step 7 until [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end).
Register callback handlers with [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) only for those events you're interested in.
## Settings
**Available 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), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event), [^silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#silence)
**Available iterators:** _none_
**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)
**Available runtime settings:** [->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), [audio-stream-from](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#audio-stream-from), [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)
**Available configuration 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), [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), [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), [trailing-silence](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#trailing-silence)
**Available values:** [vad](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#vad)
**Also see these related items:** [live-segment.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-segment.md#live-segment-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code), [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudio-code)
*[API]: Application Programming Interface
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
*[VAD]: Voice Activity Detector
---
source_path: "models/types/wake-word.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/models/types/wake-word/"
---
# Wake word
Fixed and enrolled wake words, and command sets.
Wake word models 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 filenames that
by convention match `spot-*.snsr`
You can create custom wake words and command sets with [VoiceHub](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub) or
[wake word enrollment](https://doc.sensory.com/tnl/7.8/models/types/enroll.md#enroll-type).
**Also see these related items:** [Wake word models](https://doc.sensory.com/tnl/7.8/models/index.md#wake-word-models) included in this distribution.
## Operation
```mermaid
flowchart TD
start((start))
fetch[/samples from ->audio-pcm/]
audio(^sample-count)
process[process]
result(^result)
start --> fetch
fetch --> audio
audio --> process
process --> fetch
process -->|recognize| result
result --> fetch
```
Recognition flow.
1. Read audio data from [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm).
2. Invoke [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event).
3. Invoke [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result) if processing detects a vocabulary phrase.
4. Continue processing until [STREAM_END](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_stream_end) occurs on [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm),
or one of the event handlers returns a code other than [OK](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_ok).
Register callback handlers with [setHandler](https://doc.sensory.com/tnl/7.8/api/inference.md#sethandler) only for those events you're interested in.
## Settings
**Available events:** [^result](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#result), [^sample-count](https://doc.sensory.com/tnl/7.8/api/setting-keys/events.md#sample-count-event)
**Available iterators:** [operating-point-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#operating-point-iterator), [vocab-iterator](https://doc.sensory.com/tnl/7.8/api/setting-keys/iterators.md#vocab-iterator)
**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)
**Available runtime settings:** [->audio-pcm](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#-audio-pcm), [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), [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)
**Available configuration settings:** [audio-stream-size](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#audio-stream-size), [delay](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#delay), [dsp-target](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#dsp-target), [duration-ms](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#duration-ms), [listen-window](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#listen-window), [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), [samples-per-second](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#samples-per-second), [sv-threshold](https://doc.sensory.com/tnl/7.8/api/setting-keys/configuration.md#sv-threshold)
**Available values:** [phrasespot](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#phrasespot)
**Also see these related items:** [live-spot.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-spot.md#live-spot-code), [snsr-eval.c](https://doc.sensory.com/tnl/7.8/api/sample/c/snsr-eval.md#snsr-eval-code), [PhraseSpot.java](https://doc.sensory.com/tnl/7.8/api/sample/android/enroll-trigger.md#et-code), [segmentSpottedAudio.java](https://doc.sensory.com/tnl/7.8/api/sample/java/segmentSpottedAudio.md#segmentspottedaudio-code)
*[API]: Application Programming Interface
*[FR]: False Reject: the recognizer did not trigger when the target phrase was spoken
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
---
source_path: "reference/index.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/reference/"
---
# Reference
This section provides reference documentation for the TrulyNatural SDK.
[Overview](https://doc.sensory.com/tnl/7.8/reference/overview.md#ref-overview)
- SDK variants, development host requirements, supported target platforms, models, tools, and license keys.
[Command-line tools](https://doc.sensory.com/tnl/7.8/tools/index.md#command-line-tools)
- Utilities for running and constructing models.
[Models](https://doc.sensory.com/tnl/7.8/models/index.md#models)
- Sample models included in this distribution.
[Model types](https://doc.sensory.com/tnl/7.8/models/types/index.md#model-types)
- Descriptions of various model types and their behaviors.
[Licenses](https://doc.sensory.com/tnl/7.8/licenses/index.md#sensory-sdk-license)
- Sensory and third-party legal agreements.
[Changelog](https://doc.sensory.com/tnl/7.8/changes/index.md#v7-changes)
- Changes by TrulyNatural SDK version.
[How to upgrade](https://doc.sensory.com/tnl/7.8/upgrade.md#how-to-upgrade)
- Change to a different SDK type or upgrade to a newer version.
[VoiceHub](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub)
- Guide to selecting the appropriate format for models created with
[Sensory's VoiceHub portal][vh].
[Contact information](https://doc.sensory.com/tnl/7.8/contact.md#contact)
- How to get in touch with Sensory.
[vh]: https://www.sensory.com/voicehub/ "Create a custom voice recognizer quickly and easily"
*[SDK]: Software Development Kit
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
---
source_path: "reference/overview.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/reference/overview/"
---
# Overview
This section provides a brief overview of this SDK: Features supported by [variant](https://doc.sensory.com/tnl/7.8/reference/overview.md#variants),
development host [requirements](https://doc.sensory.com/tnl/7.8/reference/overview.md#requirements), [supported target platforms](https://doc.sensory.com/tnl/7.8/reference/overview.md#supported-target-platforms), `snsr` [model](https://doc.sensory.com/tnl/7.8/reference/overview.md#ref-models) files,
command-line [tools](https://doc.sensory.com/tnl/7.8/reference/overview.md#ref-tools), and the software [license keys](https://doc.sensory.com/tnl/7.8/reference/overview.md#license-keys) we use to control library features.
## Variants
The TrulyHandsfree, TrulyNatural (Lite), and TrulyNatural STT SDKs differ **only** in
the types of models they support. The APIs, model formats, tools, etc. are identical.
TrulyNatural STT is a strict superset of TrulyNatural (Lite), which in turn
is a strict superset of TrulyHandsfree.
**[TrulyNatural STT][tnl-stt]:**
* [x] Speech-To-Text with transformers and compressed language models.
* [x] Recognition hypotheses include punctuation and capitalization.
* [x] Machine-learned NLU for intent and entity identification.
* [x] Generative language models.
* [x] **Sensory has models available for 35 languages**,
each in multiple sizes (for best accuracy given a CPU cycle budget).
Please contact your account representative or [Sensory Sales](https://doc.sensory.com/tnl/7.8/contact.md#sales) for
details.
* [x] _Includes [Open Source software](https://doc.sensory.com/tnl/7.8/licenses/oss.md#open-source-licenses)._
* [x] Features available in TrulyNatural STT only are flagged with _(stt)_
**[TrulyNatural Lite][tnl-lite]:**
* [x] Phonemic acoustic models with FST vocabulary decoding.
* [x] [Grammar-based](https://doc.sensory.com/tnl/7.8/models/types/lvcsr.md#grammar-based-recognition) medium vocabulary command and control.
* [x] Grammar-based NLU for intent and entity identification.
* [x] Tools to build recognizers from grammars or phrase lists.
* [x] API to build or augment recognizers at runtime.
* [x] Runs [VoiceHub](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub) "large natural language vocabulary" models.
* [x] Support for devices with limited RAM (< 1 MiB) and CPU (< 500 MHz).
* [x] _No third-party or Open Source software._
* [x] Features available in TrulyNatural (Lite and STT) only are flagged with _(tnl)_
**[TrulyHandsfree][thf]:**
* [x] [Fixed](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type), [enrolled](https://doc.sensory.com/tnl/7.8/models/types/enroll.md#enroll-type) and [adapting](https://doc.sensory.com/tnl/7.8/models/types/ca.md#ca-type) wake words.
* [x] Command sets, which are keyword spotter recognizers for multiple (up to twenty) active phrases.
* [x] [VAD](https://doc.sensory.com/tnl/7.8/api/setting-keys/values.md#vad).
* [x] [Command-line tools](https://doc.sensory.com/tnl/7.8/tools/index.md#command-line-tools) to enroll and evaluate wake word models, and to convert wake word models
into Sensory's THF Micro DSP format.
* [x] Runs [VoiceHub](https://doc.sensory.com/tnl/7.8/reference/voicehub.md#voicehub) "wake word" and "simple commands" projects.
* [x] _No third-party or Open Source software._
## Requirements
For development, you'll need:
- macOS, x86_64 Linux, or
Windows (version 10 or later, [Microsoft Visual Studio][msvc] 2022)
development machine.
- iOS: [Xcode] 26.5 or later.
- Java: [Java JDK][jdk] 11 through 21.
- Android: [Android Studio Panda][as] 2025.3.4 or later.
[API level 21][api-levels] or later.
**Verified with:**
TrulyNatural SDK 7.8.0-pre.0+682.g276c2541e9 was verified against
**Xcode 26.5** and **Android Studio Panda 4 | 2025.3.4 Patch 1**.
Newer point releases are expected to work but are not part of the
release-test matrix.
Models require audio encoded as 16-bit LPCM and sampled at 16 kHz.
For optimal recognition accuracy, ensure that the dynamic range of the input audio
spans **at least** 12 bits (-24 [dBFS][] peak-to-peak, sample values
from -2048 to 2047) and that no clipping is present.
## Supported target platforms
TrulyHandsfree and TrulyNatural run on hundreds of different operating systems
and CPU combinations. This distribution includes a subset of these in
_~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/lib/_. See the `README` files in the platform subdirectories
for additional details, such as the toolchain and compiler flags used to build the library.
TrulyNatural STT is available for Android, iOS on `arm64` and `arm64e`, macOS, Linux on `x86_64`, `aarch64`, and `arm`,
and Windows on `x86_64`.
[Contact](https://doc.sensory.com/tnl/7.8/contact.md#contact) us if your target platform isn't listed.
Platform { data-sort-default }| STT support| Note
:-----------------------------|:----------:|:----
`aarch64-linux-gnu` | • yes | [GLIBC][] >= 2.33
`arm-linux-gnueabi` | • no | [GLIBC][] >= 2.17
`arm-linux-gnueabihf` | • yes | [GLIBC][] >= 2.33
`arm-none-eabi` | • no
`arm-none-eabihf` | • no
`arm-none-eabihf-ethosu` | • no
`armv6-linux-gnueabihf` | • no | [GLIBC][] >= 2.17
`i686-linux-gnu` | • no | [GLIBC][] >= 2.17
`ios` | • yes | 64-bit only
`android` | • yes | [API level][api-levels] >= 21
`macos` | • yes
`mipsel-buildroot-linux-uclibc` | • no
`mipsel-openwrt-linux-musl` | • no
`x86_64-linux-gnu` | • yes | [GLIBC][] >= 2.17
`x86_64-windows-msvc` | • yes | Requires [MSVC Runtime][] 2022
*Included target platform libraries*
## Models
TrulyNatural SDK `.snsr` files include all the models and settings required for a task, and a flow
graph that defines the behavior. A task can be as simple as a single-phrase [wake word](https://doc.sensory.com/tnl/7.8/models/types/wake-word.md#wake-word-type),
or something more complicated such as wake word followed by a VAD and an STT recognizer that transcribes
the detected speech segment. If you're just interested in the final recognition results, the code required
to run these two examples is identical.
This distribution includes sample [models](https://doc.sensory.com/tnl/7.8/models/index.md#models) and [templates](https://doc.sensory.com/tnl/7.8/models/index.md#templates) used to add additional behaviors to these.
## Tools
The _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/bin/_ directory contains a number of [command-line tools](https://doc.sensory.com/tnl/7.8/tools/index.md#command-line-tools). These evaluate models,
compose new models, modify settings, enroll wake words, convert wake word models to THF Micro DSP format,
and diagnose audio recording quality.
These utilities are compiled for the development host. You can [compile these from source](https://doc.sensory.com/tnl/7.8/api/sample/c/index.md#c-examples) for other
platforms.
## License keys
The TrulyNatural SDK installer embeds the license key entered on the
"Product Licensing" page in the libraries and tools it installs.
All applications that link against these libraries include this license key.
Keys include the SDK licensee name.
We use license keys to control access to specific SDK features,
target platforms, CPU architectures, and to specify an expiration date
for access.
Model files also include license keys. These are validated upon loading.
License keys fall into two broad categories: _development_ ones which
either expire at some future date or limit use, and
_production_ keys which do not expire and do not have usage limits.
_(since [7.7.0](https://doc.sensory.com/tnl/7.8/changes/index.md#v7.7.0))_ You can use the [LICENSE](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_license) option
to apply an updated license key with the [configuration](https://doc.sensory.com/tnl/7.8/api/library-config.md#config) API
at runtime.
**Warning:**
Do _not_ use development / expiring keys in shipping products. These will
stop working when the keys expire.
[Contact](https://doc.sensory.com/tnl/7.8/contact.md#contact) Sensory to obtain production-ready libraries and models.
**Also see these related items:** [license-exp-date](https://doc.sensory.com/tnl/7.8/api/setting-keys/library-information.md#license-exp-date), [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), [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-license-exp-warn](https://doc.sensory.com/tnl/7.8/api/setting-keys/runtime.md#model-license-exp-warn), [LICENSE](https://doc.sensory.com/tnl/7.8/api/library-config.md#config_license), [LICENSE_NOT_VALID](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [LICENSE_LIMIT_EXCEEDED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc), [LICENSE_OVERRIDE_NOT_SUPPORTED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_license_override_not_supported), [LICENSE_OVERRIDE_NOT_ENABLED](https://doc.sensory.com/tnl/7.8/api/inference.md#rc_license_override_not_enabled)
[api-levels]: https://en.wikipedia.org/wiki/Android_version_history "Android version history and API levels"
[as]: https://developer.android.com/studio/index.html "Android Studio"
[dBFS]: https://en.wikipedia.org/wiki/DBFS "Decibels relative to full scale"
[GLIBC]: https://sourceware.org/glibc/wiki/Glibc%20Timeline "GNU C Library Release Timeline"
[jdk]: https://adoptium.net "Java Development Kit"
[msvc]: https://visualstudio.com/ "Microsoft Visual Studio"
[MSVC Runtime]: https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#visual-studio-2015-2017-2019-and-2022 "Microsoft Visual C++ Redistributable"
[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
*[FST]: Finite-State Transducer
*[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
*[OSS]: Open-source software
*[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
*[VAD]: Voice Activity Detector
---
source_path: "reference/voicehub.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/reference/voicehub/"
---
# VoiceHub
[Sensory's VoiceHub][vh] is a web portal that provides a convenient interface for
developers to prototype and experiment with wake words, language models and natural
language understanding. Users can build custom wake words, voice control command sets, and
create grammar-based language models with flexible intents and entities.
VoiceHub uses Sensory's [TrulyHandsfree][thf] for wake words and spotted commands,
and [TrulyNatural][tnl-lite] for grammar-based recognition with natural language
markup to identify intents and entities.
## Output format selection
VoiceHub can deliver recognizer models in various formats, as specified by the `Output Format`
selector. If you want to use such a model with the TrulyHandsfree or TrulyNatural SDKs
you should select the `THF/TNL SDK: snsr file` option. This is the default for new projects.
If you are using TrulyHandsfree or TrulyNatural on a small embedded platform,
you should select one of the alternate output formats described below.
**`THF/TNL SDK: snsr file`** _(recommended)_
- This is the standard TrulyNatural model format. Use this unless you will be running the model
on an embedded platform with limited CPU cycles and available RAM.
**`THF/TNL SDK: snsr file (low memory use)`**
- This optimizes the model for small platforms with limited CPU cycles (< 500 MHz)
and RAM (< 1 MiB of heap). The reduced heap and CPU requirements come at the expense
of a bit of recognition accuracy.
**`THF/TNL SDK: .c file (low memory use)`**
- Similar to `THF/TNL SDK: snsr file (low memory use)` above, but also includes a model converted
to C code that you can compile into your application. On platforms with read-only / flash
memory this reduces the amount of RAM required by the size of the model file.
- VoiceHub uses [snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit) to create two C files from the `snsr` model:
- `snsr-edit -c voicehub -t model.snsr` to create _model.c_, and
- `snsr-edit -i -t model.snsr -o model-custom-init.c` to create _model-custom-init.c_. This file
includes custom initialization code that elides unused modules at link time to [reduce overall
application size](https://doc.sensory.com/tnl/7.8/faq.md#reduce-code-size).
**`THF/TNL SDK: .c file (low memory use for ST Micro STM32H7)`**
- Similar to `THF/TNL SDK: .c file (low memory use)`, but also includes TrulyNatural SDK libraries
for use on the STMicroelectronics [STM32H7][] series microcontrollers.
**`Embedded: Arm Cortex-M55/M85 Ethos-U55-128`**
- Similar to `THF/TNL SDK: .c file (low memory use)`, but with inference optimized for Arm's
Cortex-M55/M85 and [Ethos-U55][] NPU with [Vela][] accelerator config `ethos-u55-128`.
- Use this on the [Alif Ensemble][] family of microcontrollers.
**`Embedded: Arm Cortex-M55/M85 Ethos-U55-256`**
- Similar to `THF/TNL SDK: .c file (low memory use)`, but with inference optimized for Arm's
Cortex-M55/M85 and [Ethos-U55][] NPU with [Vela][] accelerator config `ethos-u55-256`.
- Use this on the [Alif Ensemble][] family of microcontrollers.
**`Embedded: Infineon Arm Cortex-M55/M85 Ethos-U55-128 (model in RAM)`**
- Similar to `THF/TNL SDK: .c file (low memory use)`, but with inference optimized for Arm's
Cortex-M55/M85 and [Ethos-U55][] NPU with [Vela][] accelerator config `ethos-u55-128`.
- The compiled model code runs from RAM. This requires more available heap than the
`(model in ROM/Flash)` option below. Use this only if the flash read speed is too low
to allow the model to run in real time.
- Use this only on Infineon microcontrollers.
**`Embedded: Infineon Arm Cortex-M55/M85 Ethos-U55-128 (model in ROM/Flash)`**
- Similar to `THF/TNL SDK: .c file (low memory use)`, but with inference optimized for Arm's
Cortex-M55/M85 and [Ethos-U55][] NPU with [Vela][] accelerator config `ethos-u55-128`.
- The compiled model code runs from code space.
- Use this only on Infineon microcontrollers.
[Alif Ensemble]: https://alifsemi.com/products/ensemble/ "The Alif Ensemble family of Arm-based 32-bit microcontrollers"
[Ethos-U55]: https://developer.arm.com/Processors/Ethos-U55 "Arm Ethos-U NPU family"
[STM32H7]: https://www.st.com/en/microcontrollers-microprocessors/stm32h7-series.html
[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"
[Vela]: https://developer.arm.com/documentation/109267/0102/Tool-support-for-the-Arm-Ethos-U-NPU/Ethos-U-Vela-compiler "Ethos-U Vela compiler"
[vh]: https://www.sensory.com/voicehub/ "Create a custom voice recognizer quickly and easily"
*[RAM]: Random Access Memory
*[ROM]: Read-Only Memory, typically nonvolatile flash memory
*[SDK]: Software Development Kit
*[THF]: TrulyHandsfree, Sensory's wake word and command recognition technology
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
---
source_path: "tools/audio-check.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/tools/audio-check/"
---
# audio-check
This tool runs checks on the audio for problems such as all-zero runs or clipping.
Also estimates signal-to-noise ratio.
The audio file should be a WAV file, mono, 16 KHz.
## Usage
```
Reports audio file quality.
usage: audio-check wavfile
options:
-v [-v [-v]] : increase verbosity
```
## Example
```console
% audio-check sampleAudio.wav
Clipping/Saturation:
No clipping / saturation - OK
Flat Waveform:
Problem: Flat for 1 msec.
Signal-to-Noise Ratio
Problem: low signal-to-noise ratio.
SNR estimate: 9.19 dBA (poor)
```
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
---
source_path: "tools/index.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/tools/"
---
# Command-line tools
The TrulyNatural SDK includes a number of command-line utilities.
Find executables for the host platform in _~/Sensory/TrulyNaturalSDK/7.8.0-pre.0+682.g276c2541e9/bin/_
## Tools
[snsr-eval](https://doc.sensory.com/tnl/7.8/tools/snsr-eval.md#snsr-eval)
- Evaluates / runs TrulyNatural SDK `.snsr` model files.
[snsr-edit](https://doc.sensory.com/tnl/7.8/tools/snsr-edit.md#snsr-edit)
- Edits/modifies TrulyNatural SDK `.snsr` model files.
[spot-enroll](https://doc.sensory.com/tnl/7.8/tools/spot-enroll.md#spot-enroll)
- Enrolls TrulyNatural SDK wake words on audio files.
[live-enroll](https://doc.sensory.com/tnl/7.8/tools/live-enroll.md#live-enroll)
- Enrolls TrulyNatural SDK wake words on live audio.
[snsr-eval-batch](https://doc.sensory.com/tnl/7.8/tools/snsr-eval-batch.md#snsr-eval-batch)
- Runs a TrulyNatural SDK `.snsr` model file on test data
and reports the false accept rate, false reject ratio, optional
word-error rate, and execution speed
[spot-convert](https://doc.sensory.com/tnl/7.8/tools/spot-convert.md#spot-convert)
- Converts TrulyNatural SDK wake word models to THF Micro format.
[snsr-log-split](https://doc.sensory.com/tnl/7.8/tools/snsr-log-split.md#snsr-log-split)
- Splits spotter log files into an event log, captured audio data,
and the source spotter model.
[audio-check](https://doc.sensory.com/tnl/7.8/tools/audio-check.md#audio-check)
- Reports audio file quality.
*[SDK]: Software Development Kit
*[THF]: TrulyHandsfree, Sensory's wake word and command recognition technology
*[TNL]: TrulyNatural, Sensory's large-vocabulary speech recognition technology
---
source_path: "tools/live-enroll.md"
canonical_url: "https://doc.sensory.com/tnl/7.8/tools/live-enroll/"
---
# live-enroll
Interactive command-line phrase spotter enrollment, using the default audio
capture device.
**Also see these related items:** [live-enroll.c](https://doc.sensory.com/tnl/7.8/api/sample/c/live-enroll.md#live-enrollc)
## Usage
```
Enrolls TrulyNatural SDK wake words on live audio.
usage: live-enroll -t task [options] +user1 [+user2 ...] [file ...]
options:
-e enrollments : enrollment context output filename
-o out : enrolled model output filename (default: enrolled-sv.snsr)
-p prefix : capture each enrollment to file as
-