English, Chinese (Mandarin), French, German, Italian, Japanese, Korean, Portuguese, and Spanish.
Support for additional languages is available for commercial customers on a case-by-case basis.
Performance
A comparison between accuracy and runtime metrics of Porcupine and two other widely-used libraries, PocketSphinx and
Snowboy, is provided here. Compared to the best-performing engine of
these two, Porcupine is 11.0 times more accurate and 6.5 times faster (on Raspberry Pi 3).
The engine starts processing the audio input from the microphone in realtime and outputs to the terminal when it detects
utterances of Porcupine.
For more information about .NET demos go to demo/dotnet.
Java Demos
Make sure there is a working microphone connected to your device. Then invoke the following commands from the terminal:
cd demo/java
./gradlew build
cd build/libs
java -jar porcupine-mic-demo.jar -a ${ACCESS_KEY} -k porcupine
The engine starts processing the audio input from the microphone in realtime and outputs to the terminal when it detects
utterances of Porcupine.
For more information about Java demos go to demo/java.
Flutter Demos
To run the Porcupine demo on Android or iOS with Flutter, you must have the Flutter SDK installed on your system. Once installed, you can run flutter doctor to determine any other missing requirements for your relevant platform. Once your environment has been set up, launch a simulator or connect an Android/iOS device.
Run the prepare_demo script from demo/flutter with a language code to set up the demo in the language of your
choice (e.g. de -> German, ko -> Korean). To see a list of available languages, run prepare_demo without a language code.
Run the following command from demo/flutter to build and deploy the demo to your device:
flutter run
React Native Demos
To run the React Native Porcupine demo app you will first need to set up your React Native environment. For this,
please refer to React Native's documentation.
yarn android-install # sets up environment
yarn android-run ${LANGUAGE}# builds and deploys to Android
For iOS:
yarn ios-install # sets up environment
yarn ios-run ${LANGUAGE}# builds and deploys to iOS
Replace ${LANGUAGE} with the language code of your choice (e.g. de -> German, ko -> Korean).
To see a list of available languages, run the android-run or ios-run command without a language code.
Android Demos
Using Android Studio, open
demo/android/Activity as an Android project, copy your AccessKey into MainActivity.java, select the build variant (Build > Select Build Variant...) for the desired language and then run the application.
To learn about how to use Porcupine in long-running services go to demo/android/Service.
To learn about how to use Porcupine with Android Speech to Text recognition go to demo/android/STT.
iOS Demos
The BackgroundService demo runs audio recording in the background, enabling detection of wake word while the application is not in focus and remains running in the background.
The ForegroundApp demo runs wake word detection only when the application is in focus.
Replace ${LIBRARY_PATH} with path to appropriate library available under lib, ${PLATFORM} with the
name of the platform you are running on (linux, raspberry-pi, or mac), ${AUDIO_DEVICE_INDEX} with
the index of your audio device and ${ACCESS_KEY} with your AccessKey.
Replace ${LIBRARY_PATH} with path to appropriate library available under lib, ${PLATFORM} with the
name of the platform you are running on (linux, raspberry-pi, or mac) and ${ACCESS_KEY} with your AccessKey.
keywords argument is a shorthand for accessing default keyword files shipped with the library. The default keyword
files available can be retrieved via
import pvporcupine
print(pvporcupine.KEYWORDS)
If you wish to use a non-default keyword file you need to identify its path:
When initialized, valid sample rate can be obtained using handle.sample_rate. The required frame length
(number of audio samples in an input array) is handle.frame_length. The object can be used to monitor
incoming audio as follows:
Finally, when done be sure to explicitly release the resources using handle.delete().
.NET
Install the .NET SDK using NuGet or the dotnet CLI:
dotnet add package Porcupine
The SDK exposes a factory method to create instances of the engine:
using Pv;
const string accessKey = "${ACCESS_KEY}";
var keyword = new List<BuiltInKeyword> { BuiltInKeyword.PICOVOICE };
Porcupine handle = Porcupine.FromBuiltInKeywords(accessKey, keyword);
Using the FromBuiltInKeywords constructor allows you to initialize the Porcupine engine to detect any of the free, built-in keywords that come with the library. These built-ins are represented by the BuiltInKeyword enum.
If you wish to use a custom keyword file (i.e. a keyword file generated by Picovoice Console, with a .ppn extension), you need to specify its path:
const string accessKey = "${ACCESS_KEY}";
var keywordPaths = new List<string> {
"/absolute/path/to/keyword/one",
"/absolute/path/to/keyword/two",
... }
Porcupine handle = Porcupine.FromKeywordPaths(accessKey, keywordPaths);
When initialized, the required sample rate can be obtained using handle.SampleRate. Expected frame length
(number of audio samples in an input array) is handle.FrameLength. The object can be used to monitor
incoming audio as below:
short[] getNextAudioFrame()
{
// .. get a frame of audio
return audioFrame;
}
while(true)
{
var keywordIndex = handle.Process(getNextAudioFrame())
if(keywordIndex >= 0)
{
// .. Insert detection event callback here
}
}
Porcupine will have its resources freed by the garbage collector, but to have resources freed immediately after use,
wrap it in a using statement:
using(Porcupine handle = Porcupine.FromBuiltInKeywords(
accessKey,
new List<BuiltInKeyword> { BuiltInKeyword.PICOVOICE }))
{
// .. Porcupine usage here
}
Java
The Porcupine Java binding is available from the Maven Central Repository at ai.picovoice:porcupine-java:${version}.
import ai.picovoice.porcupine.*;
// AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)
final String accessKey = "${ACCESS_KEY}";
try {
Porcupine handle = new Porcupine.Builder()
.setAccessKey(accessKey)
.setBuiltInKeyword(BuiltInKeyword.PORCUPINE)
.build();
} catch (PorcupineException e) { }
The setBuiltInKeyword() builder argument is a shorthand for accessing built-in keyword model files shipped with the package.
The list of built-in keywords can be found in the BuiltInKeyword enum, and can be retrieved by:
If you wish to use a custom keyword file (i.e. a keyword file generated by Picovoice Console, with a .ppn extension) you need to the file path as demonstrated below:
import ai.picovoice.porcupine.*;
// AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)
final String accessKey = "${ACCESS_KEY}";
try {
Porcupine handle = new Porcupine.Builder()
.setAccessKey(accessKey)
.setKeywordPath("path/to/custom/keyword/file")
.build();
} catch (PorcupineException e) { }
When initialized, valid sample rate can be obtained using handle.getSampleRate(). Expected frame length
(number of audio samples in an input array) is handle.getFrameLength(). The object can be used to monitor
incoming audio as below:
PorcupineManager provides a high-level API that takes care of audio recording. This class is the quickest way to get started.
The static constructor PorcupineManager.fromBuiltInKeywords will create an instance of the PorcupineManager using one or more of the built-in keywords.
To create an instance of PorcupineManager that detects custom keywords, you can use the PorcupineManager.fromKeywordPaths static constructor and provide the paths to the .ppn file(s).
Once you have instantiated a PorcupineManager, you can start/stop audio capture and wake word detection by calling:
try {
await _porcupineManager.start();
} onPorcupineExceptioncatch (ex) {
// deal with either audio exception
}
// .. use porcupineawait _porcupineManager.stop();
Once the app is done with using PorcupineManager, be sure you explicitly release the resources allocated to Porcupine:
await _porcupineManager.delete();
There is no need to deal with audio capture to enable wake word detection with PorcupineManager.
This is because it uses flutter_voice_processor plugin to capture frames of audio and automatically pass it to the wake word engine.
Low-Level API
Porcupine provides low-level access to the wake word engine for those who want to incorporate wake word detection into an already existing audio processing pipeline.Porcupine has fromBuiltInKeywords and fromKeywordPaths static constructors.
To search for a keyword in audio, you must pass frames of audio to Porcupine using the process function. The keywordIndex returned will either be -1 if no detection was made or an integer specifying which keyword was detected.
To create an instance of PorcupineManager that detects custom keywords, you can use the PorcupineManager.fromKeywordPaths
static constructor and provide the paths to the .ppn file(s).
Once you have instantiated a Porcupine manager, you can start/stop audio capture and wake word detection by calling:
let didStart = this._porcupineManager.start();
// .. use Porcupinelet didStop = this._porcupineManager.stop();
Once the app is done with using PorcupineManager, be sure you explicitly release the resources allocated to Porcupine:
this._porcupineManager.delete();
There is no need to deal with audio capture to enable wake word detection with PorcupineManager.
This is because it uses @picovoice/react-native-voice-processor
module to capture frames of audio and automatically pass it to the wake word engine.
Low-Level API
Porcupine provides low-level access to the wake word engine for those
who want to incorporate wake word detection into an already existing audio processing pipeline. Porcupine also has
fromBuiltInKeywords and fromKeywordPaths static constructors.
To search for a keyword in audio, you must pass frames of audio to Porcupine using the process function. The keywordIndex returned will either be -1 if no detection was made or an integer specifying which keyword was detected.
let buffer = getAudioFrame();
try {
let keywordIndex = awaitthis._porcupine.process(buffer);
if (keywordIndex >= 0) {
// detection made!
}
} catch (e) {
// handle error
}
For process to work correctly, the provided audio must be single-channel and 16-bit linearly-encoded.
Finally, once you no longer need the wake word engine, be sure to explicitly release the resources allocated to Porcupine:
this._porcupine.delete();
Android
To include the package in your Android project, ensure you have included mavenCentral() in your top-level build.gradle file and then add the following to your app's build.gradle:
There are two possibilities for integrating Porcupine into an Android application.
High-Level API
PorcupineManager
provides a high-level API for integrating Porcupine into Android applications. It manages all activities related to creating
an input audio stream, feeding it into the Porcupine library, and invoking a user-provided detection callback.
import ai.picovoice.porcupine.*;
final String accessKey = "${ACCESS_KEY}"; // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)
final String keywordPath = "/path/to/keyword.ppn"; // path relative to 'assets' folder
try {
PorcupineManager porcupineManager = new PorcupineManager.Builder()
.setAccessKey(accessKey)
.setKeywordPath(keywordPath)
.setSensitivity(0.5f)
.build(context,
new PorcupineManagerCallback() {
@Override
public void invoke(int keywordIndex) {
// detection event logic/callback
}
});
} catch (PorcupineException e) { }
Keyword files (.ppn) should be placed under the Android project assets folder (src/main/assets/).
Sensitivity is the parameter that enables developers to trade miss rate for false alarm. It is a floating point number within
[0, 1]. A higher sensitivity reduces miss rate at cost of increased false alarm rate.
When initialized, input audio can be monitored using manager.start(). Stop the manager using by invoking
manager.stop(). When done be sure to release the resources using manager.delete().
Low-Level API
Porcupine provides a
binding for Android. It can be initialized using:
import ai.picovoice.porcupine.*;
final String accessKey = "${ACCESS_KEY}";
final String keywordPath = "/path/to/keyword.ppn";
try {
Porcupine porcupine = new Porcupine.Builder()
.setAccessKey(accessKey)
.setKeywordPath(keywordPath)
.setSensitivity(0.5f)
.build(context);
} catch (PorcupineException e) { }
Once initialized, porcupine can be used to monitor incoming audio.
private short[] getNextAudioFrame();
while (true) {
final int keywordIndex = porcupine.process(getNextAudioFrame());
if (keywordIndex != -1) {
// detection event logic/callback
}
}
Finally, be sure to explicitly release resources acquired by porcupine as the binding class does not rely on the garbage collector for releasing native resources.
porcupine.delete();
iOS
There are two approaches for integrating Porcupine into an iOS application.
High-Level API
PorcupineManager manages audio recording, passing it into Porcupine, and invoking
the user-provided detection callback.
let accessKey = "${ACCESS_KEY}" // Obtained from Picovoice Console (https://console.picovoice.ai)
let modelPath: String = ... // Available at lib/common/porcupine_params.pv
let keywordPaths: [String] = ["/path/to/keyword/file/a", "/path/to/keyword/file/b"]
let sensitivities: [Float32] = [0.35, 0.64]
let keywordCallback: ((Int32) -> Void) = { keywordIndex in
// Insert detection event logic
}
let manager = try PorcupineManager(
accessKey: accessKey,
modelPath: modelPath,
keywordPaths: keywordPaths,
sensitivities: sensitivities
onDetection: keywordCallback)
When initialized, input audio can be monitored using manager.start(). When done be sure to stop the manager using
manager.stop().
Low-Level API
Porcupine.swift provides low-level access to the wake word engine for those who want to incorporate wake word detection into an already existing audio processing pipeline.
To construct an instance of Porcupine, pass it a keyword.
import Porcupine
let accessKey = "${ACCESS_KEY}" // Obtained from Picovoice Console (https://console.picovoice.ai)
do {
Porcupine porcupine = try Porcupine(
accessKey: accessKey,
keyword: Porcupine.BuiltInKeyword.picovoice)
} catch { }
To search for a keyword in audio, you must pass frames of audio to Porcupine using the process function. The keywordIndex returned will either be -1 if no detection was made or an integer specifying which keyword was detected.
func getNextAudioFrame() -> [Int16] {
// .. get audioFrame
return audioFrame;
}
while true {
do {
let keywordIndex = try porcupine.process(getNextAudioFrame())
if keywordIndex >= 0 {
// .. detection made!
}
} catch { }
}
Once you're done with Porcupine you can force it to release its native resources rather than waiting for the garbage collector:
porcupine.delete();
Web
Porcupine is available on modern web browsers (i.e. not Internet Explorer) via WebAssembly. Microphone audio is handled via the Web Audio API and is abstracted by the WebVoiceProcessor, which also handles downsampling to the correct format. Porcupine is provided pre-packaged as a Web Worker.
Vanilla JavaScript and HTML (CDN Script Tag)
<!DOCTYPE html><htmllang="en"><head><scriptsrc="https://unpkg.com/@picovoice/porcupine-web/dist/iife/index.js"></script><scriptsrc="https://unpkg.com/@picovoice/web-voice-processor/dist/iife/index.js"></script><scripttype="application/javascript">constPORCUPINE_MODEL_BASE64 = /* Base64 representation of the `.pv` model file*/;
functionkeywordDetectionCallback(detection) {
console.log(`Porcupine detected ${detection.label}`);
}
functionprocessErrorCallback(error) {
console.error(error);
}
asyncfunctionstartPorcupine() {
console.log("Porcupine is loading. Please wait...");
const accessKey = "${ACCESS_KEY}"// Obtained from Picovoice Console (picovoice.ai/console/)let porcupine = awaitPorcupineWeb.PorcupineWorker.create(
accessKey,
[PorcupineWeb.BuiltInKeyword.Picovoice],
porcupineKeywordCallback,
{ base64: PORCUPINE_MODEL_BASE64 },
);
console.log("Porcupine worker ready!");
console.log("WebVoiceProcessor initializing. Microphone permissions requested ...");
awaitwindow.WebVoiceProcessor.WebVoiceProcessor.subscribe(porcupine);
console.log("WebVoiceProcessor ready and listening!");
document.addEventListener("DOMContentLoaded", function () {
startPorcupine();
});
</script></head><body></body></html>
Create instances of the Porcupine class by specifying which keywords you want it to listen for:
const {
Porcupine,
BuiltinKeyword,
}= require("@picovoice/porcupine-node");
// Obtained from the Picovoice Console (https://console.picovoice.ai/)const accessKey = "${ACCESS_KEY}";
let handle = newPorcupine(
accessKey,
[BuiltinKeyword.GRASSHOPPER, BuiltinKeyword.BUMBLEBEE],
[0.5, 0.65]);
GRASSHOPPER and BUMBLEBEE are built-in keywords. If you wish to use a custom keyword file, you need to identify its path:
constPorcupine = require("@picovoice/porcupine-node");
// Obtained from the Picovoice Console (https://console.picovoice.ai/)const accessKey = "${ACCESS_KEY}";
let handle = newPorcupine(
accessKey,
["/path/to/custom/keyword/file"],
[0.5]);
When instantiated, handle can process audio via its .process method.
let getNextAudioFrame = function() {
...
};
while (true) {
let keywordIndex = handle.process(getNextAudioFrame());
if (keywordIndex !== -1) {
// detection event callback
}
}
When done be sure to release resources acquired by WebAssembly using release():
handle.release();
C
Porcupine is implemented in ANSI C and therefore can be directly linked to C applications.
include/pv_porcupine.h header file contains relevant information. An instance of Porcupine
object can be constructed as follows.
Sensitivity is the parameter that enables developers to trade miss rate for false alarm. It is a floating point number
within [0, 1]. A higher sensitivity reduces miss rate (false reject rate) at cost of (potentially) increased false alarm
rate.
Now the handle can be used to monitor incoming audio stream. Porcupine accepts single channel, 16-bit linearly-encoded
PCM audio. The sample rate can be retrieved using pv_sample_rate(). Finally, Porcupine accepts input audio in
consecutive chunks (aka frames) the length of each frame can be retrieved using pv_porcupine_frame_length().
Finally, when done be sure to release the acquired resources:
pv_porcupine_delete(handle);
Microcontroller
Porcupine is implemented in ANSI C and therefore can be directly linked to embedded C projects. Its public header file contains relevant information. An instance of the Porcupine object can be constructed as follows.
Sensitivity is the parameter that enables developers to trade miss rate for false alarm. It is a floating-point number
within [0, 1]. A higher sensitivity reduces miss rate (false reject rate) at cost of increased false alarm rate.
Now the handle can be used to monitor incoming audio stream. Porcupine accepts single channel, 16-bit PCM audio. The
sample rate can be retrieved using pv_sample_rate(). Finally, Picovoice accepts input audio in consecutive chunks (aka
frames) the length of each frame can be retrieved using pv_porcupine_frame_length().