Skip to content

Your first program

If you followed Command-line tools, you already ran a wake word with 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 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).
  • 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.
  • JDK 17 or later and Gradle 8.0 or later (or use a Gradle wrapper).
  • A microphone (Java Audio capture via fromAudioDevice).
  • A phrase-spot .snsr file (same voice genie model path as the C tab).
  • 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.
  • 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.

The program

The program below mirrors the pull-mode recipe in API overview: create a Session, load a spotter model, attach live audio, register a ^result handler, call run, then release.

This is a teaching sketch (minimal error handling). The shipped sample live-spot.c adds timing in the callback, full RC checks, and more.

Create first-spot.c with:

#include <snsr.h>
#include <stdio.h>
#include <stdlib.h>

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 — allocate an empty Session handle.
  2. load the .snsr model from disk (pass a phrase-spot .snsr file, as on the Command-line tools page).
  3. setStream attaches live PCM from the default capture device (fromAudioDevice).
  4. setHandler registers resultEvent on the ^result event (callback).
  5. run blocks until the handler returns STOP or an error RC.
  6. On any code other than STOP, print errorDetail to stderr (same pattern as live-spot.c). The handler propagates RC errors from getString.
  7. release frees the session and attached streams.

Create FirstSpot.java with:

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 (new).
  2. load the .snsr model from the path in argv[0].
  3. setStream with fromAudioDevice on the method chain.
  4. setHandler on ^result; return STOP to end run.
  5. run — pull-mode loop until the handler stops.
  6. release the session.

Look up signatures under the Java tabs on Inference and I/O. The Java binding throws on failure instead of latched RC codes (see API overview § Language bindings).

Uses the Java Session API — see Java tabs on Inference for method details. The excerpt is the core wake-word-only flow in snsr-debug; the shipping app also uses a worker thread, UI, and optional debug logging.

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.

Calls the C API from Swift — look up snsrLoad, snsrSetStream, and related functions under the C tabs on Inference and I/O. There is no Swift Session wrapper; PhraseSpot uses a bridging header and runs run on a background queue.

// 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

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_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 (CMake is the recommended approach on Linux, macOS, and Windows). Using GNU Make only? See Integrate with your build § Make and C examples § Build with GNU Make.

  3. Configure and build:

    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 for toolchain notes.

  4. Run the spotter. Say “voice genie” a few times:

    ./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 with STOP).

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:

    rootProject.name = 'first-spot'
    
  3. Create build.gradle in the project root:

    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.

  4. From the project root, configure and run:

    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.

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). These commands expect FirstSpot.java in the current directory:

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).

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).

  2. Connect a device or start an emulator with microphone support.

  3. Build and install (no edits to sample sources):

    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).

Integrate in your own app

Use the Program excerpt as a guide, then follow Integrate with your build § Android and the Android examples. A from-scratch Android walk-through is not duplicated here (manifest, AAR, assets, and UI threading are app-specific).

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.

    The project is already configured with SNSR_ROOT, bridging header, frameworks, and NSMicrophoneUsageDescription (see build-ios).

Integrate in your own app

Use the Program excerpt and C API reference tabs, then follow Integrate with your build § iOS and 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 with new.
  2. Loaded a wake-word model.
  3. Attached a live audio source.
  4. Registered a ^result callback handler.
  5. Ran pull-mode inference with run.
  6. Released the session.

Next steps

Platform Full sample Look up API under
C live-spot.c C tabs on Inference and I/O, …
Java evalUDT.java Java tabs on Inference and I/O
Android snsr-debug Java tabs + Android examples
iOS PhraseSpot C tabs + Integrate with your build § iOS

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 ( stt), use snsr-edit with a template such as tpl-opt-spot-vad-lvcsr 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 Instructions step 3 shows this with the full sample (VAD + STT after the wake word).