{"id":1424,"url":"https://github.com/Picovoice/Porcupine","last_synced_at":"2025-08-02T04:32:02.819Z","repository":{"id":37493205,"uuid":"124321055","full_name":"Picovoice/porcupine","owner":"Picovoice","description":"On-device wake word detection powered by deep learning","archived":false,"fork":false,"pushed_at":"2025-07-22T20:13:04.000Z","size":356121,"stargazers_count":4290,"open_issues_count":0,"forks_count":537,"subscribers_count":66,"default_branch":"master","last_synced_at":"2025-07-28T13:38:25.193Z","etag":null,"topics":["handsfree","hotword","hotword-detection","hotword-detector","keyword-spotter","keyword-spotting","on-device","speech-recognition","trigger-word-detection","voice-activation","wake-word","wake-word-detection","wake-word-engine"],"latest_commit_sha":null,"homepage":"https://picovoice.ai/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Picovoice.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-03-08T01:55:25.000Z","updated_at":"2025-07-28T04:03:57.000Z","dependencies_parsed_at":"2023-10-03T01:41:12.306Z","dependency_job_id":"5b1ab03a-8699-4058-a076-d446c0f9d4b2","html_url":"https://github.com/Picovoice/porcupine","commit_stats":{"total_commits":906,"total_committers":42,"mean_commits":"21.571428571428573","dds":0.7295805739514349,"last_synced_commit":"1c25860e8775ed5c98fefb066c64fe7e271f69a4"},"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"purl":"pkg:github/Picovoice/porcupine","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Picovoice%2Fporcupine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Picovoice%2Fporcupine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Picovoice%2Fporcupine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Picovoice%2Fporcupine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Picovoice","download_url":"https://codeload.github.com/Picovoice/porcupine/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Picovoice%2Fporcupine/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268334614,"owners_count":24233793,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["handsfree","hotword","hotword-detection","hotword-detector","keyword-spotter","keyword-spotting","on-device","speech-recognition","trigger-word-detection","voice-activation","wake-word","wake-word-detection","wake-word-engine"],"created_at":"2024-01-05T20:15:46.144Z","updated_at":"2025-08-02T04:31:57.806Z","avatar_url":"https://github.com/Picovoice.png","language":"Python","funding_links":[],"categories":["Media"],"sub_categories":["Audio"],"readme":"# Porcupine\n\n[![GitHub release](https://img.shields.io/github/release/Picovoice/Porcupine.svg)](https://github.com/Picovoice/Porcupine/releases)\n[![GitHub](https://img.shields.io/github/license/Picovoice/porcupine)](https://github.com/Picovoice/porcupine/)\n[![GitHub language count](https://img.shields.io/github/languages/count/Picovoice/porcupine)](https://github.com/Picovoice/porcupine/)\n\n[![PyPI](https://img.shields.io/pypi/v/pvporcupine)](https://pypi.org/project/pvporcupine/)\n[![Nuget](https://img.shields.io/nuget/v/porcupine)](https://www.nuget.org/packages/Porcupine/)\n[![Go Reference](https://pkg.go.dev/badge/github.com/Picovoice/porcupine/binding/go.svg)](https://pkg.go.dev/github.com/Picovoice/porcupine/binding/go)\n[![Pub Version](https://img.shields.io/pub/v/porcupine_flutter)](https://pub.dev/packages/porcupine_flutter)\n[![npm](https://img.shields.io/npm/v/@picovoice/porcupine-react-native?label=npm%20%5Breact-native%5D)](https://www.npmjs.com/package/@picovoice/porcupine-react-native)\n[![Maven Central](https://img.shields.io/maven-central/v/ai.picovoice/porcupine-android?label=maven-central%20%5Bandroid%5D)](https://repo1.maven.org/maven2/ai/picovoice/porcupine-android/)\n[![Maven Central](https://img.shields.io/maven-central/v/ai.picovoice/porcupine-java?label=maven%20central%20%5Bjava%5D)](https://repo1.maven.org/maven2/ai/picovoice/porcupine-java/)\n[![npm](https://img.shields.io/npm/v/@picovoice/porcupine-angular?label=npm%20%5Bangular%5D)](https://www.npmjs.com/package/@picovoice/porcupine-angular)\n[![npm](https://img.shields.io/npm/v/@picovoice/porcupine-vue?label=npm%20%5Bvue%5D)](https://www.npmjs.com/package/@picovoice/porcupine-vue)\n[![npm](https://img.shields.io/npm/v/@picovoice/porcupine-react?label=npm%20%5Breact%5D)](https://www.npmjs.com/package/@picovoice/porcupine-react)\n[![npm](https://img.shields.io/npm/v/@picovoice/porcupine-node?label=npm%20%5Bnode%5D)](https://www.npmjs.com/package/@picovoice/picovoice-node)\n\u003c!-- markdown-link-check-disable --\u003e\n[![Crates.io](https://img.shields.io/crates/v/pv_porcupine)](https://crates.io/crates/pv_porcupine)\n\u003c!-- markdown-link-check-enable --\u003e\nMade in Vancouver, Canada by [Picovoice](https://picovoice.ai)\n\n\u003c!-- markdown-link-check-disable --\u003e\n[![Twitter URL](https://img.shields.io/twitter/url?label=%40AiPicovoice\u0026style=social\u0026url=https%3A%2F%2Ftwitter.com%2FAiPicovoice)](https://twitter.com/AiPicovoice)\n\u003c!-- markdown-link-check-enable --\u003e\n[![YouTube Channel Views](https://img.shields.io/youtube/channel/views/UCAdi9sTCXLosG1XeqDwLx7w?label=YouTube\u0026style=social)](https://www.youtube.com/channel/UCAdi9sTCXLosG1XeqDwLx7w)\n\nPorcupine is a highly-accurate and lightweight wake word engine. It enables building always-listening voice-enabled\napplications. It is\n\n- using deep neural networks trained in real-world environments.\n- compact and computationally-efficient. It is perfect for IoT.\n- cross-platform:\n  - Arm Cortex-M, STM32, Arduino, and i.MX RT\n  - Raspberry Pi, NVIDIA Jetson Nano, and BeagleBone\n  - Android and iOS\n  - Chrome, Safari, Firefox, and Edge\n  - Linux (x86_64), macOS (x86_64, arm64), and Windows (x86_64)\n- scalable. It can detect multiple always-listening voice commands with no added runtime footprint.\n- self-service. Developers can train custom wake word models using [Picovoice Console](https://console.picovoice.ai/).\n\n## Table of Contents\n\n- [Porcupine](#porcupine)\n  - [Table of Contents](#table-of-contents)\n  - [Use Cases](#use-cases)\n  - [Try It Out](#try-it-out)\n  - [Language Support](#language-support)\n  - [Performance](#performance)\n  - [Demos](#demos)\n    - [Python](#python-demos)\n    - [.NET](#net-demos)\n    - [Java](#java-demos)\n    - [Go](#go-demos)\n    - [Unity](#unity-demos)\n    - [Flutter](#flutter-demos)\n    - [React Native](#react-native-demos)\n    - [Android](#android-demos)\n    - [iOS](#ios-demos)\n    - [Web](#web-demos)\n      - [Vanilla JavaScript and HTML](#vanilla-javascript-and-html)\n      - [Angular](#angular-demos)\n      - [React](#react-demos)\n      - [Vue](#vue-demos)\n    - [NodeJS](#nodejs-demos)\n    - [Rust](#rust-demos)\n    - [C](#c-demos)\n    - [Microcontroller](#microcontroller-demos)\n  - [SDKs](#sdks)\n    - [Python](#python)\n    - [.NET](#net)\n    - [Java](#java)\n    - [Go](#go)\n    - [Unity](#unity)\n    - [Flutter](#flutter)\n    - [React Native](#react-native)\n    - [Android](#android)\n    - [iOS](#ios)\n    - [Web](#web)\n      - [Vanilla JavaScript and HTML (CDN Script Tag)](#vanilla-javascript-and-html-cdn-script-tag)\n      - [Vanilla JavaScript and HTML (ES Modules)](#vanilla-javascript-and-html-es-modules)\n      - [Angular](#angular)\n      - [React](#react)\n      - [Vue](#vue)\n    - [NodeJS](#nodejs)\n    - [Rust](#rust)\n    - [C](#c)\n    - [Microcontroller](#microcontroller)\n  - [Releases](#releases)\n  - [FAQ](#faq)\n\n## Use Cases\n\nPorcupine is the right product if you need to detect one or a few static (always-listening) voice commands.\n\n- If you want to create voice experiences similar to Alexa or Google, see the\n  [Picovoice platform](https://github.com/Picovoice/picovoice).\n- If you need to understand complex and naturally-spoken voice commands within a specific domain, see the\n  [Rhino Speech-to-Intent engine](https://github.com/Picovoice/rhino).\n\n## Try It Out\n\n- [Interactive Web Demo](https://picovoice.ai/demos/lamp/)\n\n- [Android Demo Application](https://play.google.com/store/apps/details?id=ai.picovoice.porcupine.demo\u0026hl=en)\n\n- Porcupine on a Raspberry Pi Zero\n\n[![Porcupine in Action](https://img.youtube.com/vi/Fi_IJEcNr3I/0.jpg)](https://www.youtube.com/watch?v=Fi_IJEcNr3I)\n\n## Language Support\n\n- Arabic, Dutch, English, Farsi, French, German, Hindi, Italian, Japanese, Korean, Mandarin, Polish, Portuguese, Russian, Spanish, Swedish, and Vietnamese\n- Support for additional languages is available for commercial customers on a case-by-case basis.\n\n## Performance\n\nA comparison between accuracy and runtime metrics of Porcupine and two other widely-used libraries, PocketSphinx and\nSnowboy, is provided [here](https://github.com/Picovoice/wakeword-benchmark). Compared to the best-performing engine of\nthese two, Porcupine is **11.0 times more accurate** and **6.5 times faster** (on Raspberry Pi 3).\n\n## Demos\n\nIf using SSH, clone the repository with:\n\n```console\ngit clone --recurse-submodules git@github.com:Picovoice/porcupine.git\n```\n\nIf using HTTPS, clone the repository with:\n\n```console\ngit clone --recurse-submodules https://github.com/Picovoice/porcupine.git\n```\n\n### Python Demos\n\nInstall the demo package:\n\n```console\nsudo pip3 install pvporcupinedemo\n```\n\nWith a working microphone connected to your device run the following in the terminal:\n\n```console\nporcupine_demo_mic --access_key ${ACCESS_KEY} --keywords porcupine\n```\n\nThe engine starts processing the audio input from the microphone in realtime and outputs to the terminal when it detects\nutterances of `Porcupine`.\n\nFor more information about Python demos go to [demo/python](demo/python).\n\n### .NET Demos\n\nFrom [demo/dotnet/PorcupineDemo](demo/dotnet/PorcupineDemo) run the\nfollowing in the terminal to build the demo:\n\n```console\ndotnet build -c MicDemo.Release\n```\n\nMake sure there is a working microphone connected to your device. From [demo/dotnet/PorcupineDemo](demo/dotnet/PorcupineDemo) run the\nfollowing in the terminal:\n\n```console\ndotnet run -c MicDemo.Release -- \\\n--access_key ${ACCESS_KEY} \\\n--keywords porcupine\n```\n\nThe engine starts processing the audio input from the microphone in realtime and outputs to the terminal when it detects\nutterances of `Porcupine`.\n\nFor more information about .NET demos go to [demo/dotnet](demo/dotnet).\n\n### Java Demos\n\nMake sure there is a working microphone connected to your device. Then invoke the following commands from the terminal:\n\n```console\ncd demo/java\n./gradlew build\ncd build/libs\njava -jar porcupine-mic-demo.jar -a ${ACCESS_KEY} -k porcupine\n```\n\nThe engine starts processing the audio input from the microphone in realtime and outputs to the terminal when it detects\nutterances of `Porcupine`.\n\nFor more information about Java demos go to [demo/java](demo/java).\n\n### Go Demos\n\nThe demo requires `cgo`, which on Windows may mean that you need to install a gcc compiler like [Mingw](http://mingw-w64.org) to build it properly.\n\nFrom [demo/go](demo/go) run the following command from the terminal to build and run the mic demo:\n```console\ngo run micdemo/porcupine_mic_demo.go \\\n-access_key \"${ACCESS_KEY}\" \\\n-keywords porcupine\n```\n\nThe engine starts processing the audio input from the microphone in realtime and outputs to the terminal when it detects utterances of the word `Porcupine`.\n\nFor more information about Go demos go to [demo/go](demo/go).\n\n### Unity Demos\n\nTo run the Porcupine Unity demo, import the [Porcupine Unity package](binding/unity/porcupine-3.0.1.unitypackage) into your project, open the PorcupineDemo scene and hit play. To run on other platforms or in the player, go to _File \u003e Build Settings_, choose your platform and hit the `Build and Run` button.\n\nTo browse the demo source go to [demo/unity](demo/unity).\n\n### Flutter Demos\n\nTo run the Porcupine demo on Android or iOS with Flutter, you must have the [Flutter SDK](https://flutter.dev/docs/get-started/install) 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.\n\nRun the `prepare_demo` script from [demo/flutter](./demo/flutter) with a language code to set up the demo in the language of your\nchoice (e.g. `de` -\u003e German, `ko` -\u003e Korean). To see a list of available languages, run `prepare_demo` without a language code.\n\n```console\ndart scripts/prepare_demo.dart ${LANGUAGE}\n```\n\nReplace your `AccessKey` in [lib/main.dart](./demo/flutter/lib/main.dart) file:\n\n```dart\nfinal String accessKey = \"{YOUR_ACCESS_KEY_HERE}\"; // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\n```\n\nRun the following command from [demo/flutter](demo/flutter) to build and deploy the demo to your device:\n\n```console\nflutter run\n```\n\n### React Native Demos\n\nTo run the React Native Porcupine demo app you will first need to set up your React Native environment. For this,\nplease refer to [React Native's documentation](https://reactnative.dev/docs/environment-setup).\n\nReplace your `AccessKey`, in [`App.tsx`](./demo/react-native/App.tsx) file:\n```typescript\n_accessKey: string =\"${YOUR_ACCESS_KEY_HERE}\" // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\n```\n\nNavigate to [demo/react-native](demo/react-native) to run the following commands:\n\nFor Android:\n\n```console\nyarn android-install          # sets up environment\nyarn android-run ${LANGUAGE}  # builds and deploys to Android\n```\n\nFor iOS:\n\n```console\nyarn ios-install              # sets up environment\nyarn ios-run ${LANGUAGE}      # builds and deploys to iOS\n```\n\nReplace `${LANGUAGE}` with the language code of your choice (e.g. de -\u003e German, ko -\u003e Korean).\nTo see a list of available languages, run the `android-run` or `ios-run` command without a language code.\n\n### Android Demos\n\nUsing [Android Studio](https://developer.android.com/studio/index.html), open\n[demo/android/Activity](demo/android/Activity) as an Android project, copy your AccessKey into `MainActivity.java`, select the build variant (`Build \u003e Select Build Variant...`) for the desired language and then run the application.\n\nTo learn about how to use Porcupine in long-running services go to [demo/android/Service](demo/android/Service).\n\nTo learn about how to use Porcupine with Android Speech to Text recognition go to [demo/android/STT](demo/android/STT).\n\n### iOS Demos\n\nThe 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.\nThe ForegroundApp demo runs wake word detection **only** when the application is in focus.\n\n#### BackgroundService Demo\n\nTo run the demo, go to [demo/ios/BackgroundService](demo/ios/BackgroundService) and run:\n\n```console\npod install\n```\n\nReplace `let accessKey = \"${YOUR_ACCESS_KEY_HERE}\"` in the file [ViewController.swift](demo/ios/BackgroundService/PorcupineBackgroundServiceDemo/ViewController.swift) with your `AccessKey`.\n\nThen, using [Xcode](https://developer.apple.com/xcode/), open the generated `PorcupineBackgroundServiceDemo.xcworkspace` and run the application.\n\n#### ForegroundApp Demo\n\nTo run the foreground application demo:\n\n1) Go to [ForegroundApp](./demo/ios/ForegroundApp) directory. Then run:\n\n```console\npod install\n```\n\n2) Open the `PorcupineForegroundAppDemo.xcworkspace` in XCode\n\n3) Replace `let accessKey = \"${YOUR_ACCESS_KEY_HERE}\"` in the file [ViewController.swift](./demo/ios/ForegroundApp/PorcupineForegroundAppDemo/ViewController.swift) with your `AccessKey`.\n\n4) Go to `Product \u003e Scheme` and select the scheme for the language you would like to demo (e.g. `arDemo` -\u003e Arabic Demo, `deDemo` -\u003e German Demo)\n\n5) Run the demo with a simulator or connected iOS device\n\nThe demo allows you to select any of the pre-built keywords for detection. Press start and say the selected keyword.\n\n\n### Web Demos\n\n#### Vanilla JavaScript and HTML\n\nFrom [demo/web](demo/web) run the following in the terminal:\n\n```console\nyarn\nyarn start ${LANGUAGE}\n```\n\n(or)\n\n```console\nnpm install\nnpm run start ${LANGUAGE}\n```\n\nOpen `http://localhost:5000` in your browser to try the demo.\n\n#### Angular Demos\n\nFrom [demo/angular](demo/angular) run the following in the terminal:\n\n```console\nyarn\nyarn start ${LANGUAGE}\n```\n\n(or)\n\n```console\nnpm install\nnpm run start ${LANGUAGE}\n```\n\nOpen `http://localhost:4200` in your browser to try the demo.\n\n#### React Demos\n\nFrom [demo/react](demo/react) run the following in the terminal:\n\n```console\nyarn\nyarn start ${LANGUAGE}\n```\n\n(or)\n\n```console\nnpm install\nnpm run start ${LANGUAGE}\n```\n\nOpen `http://localhost:3000` in your browser to try the demo.\n\n#### Vue Demos\n\nFrom [demo/vue](demo/vue) run the following in the terminal:\n\n```console\nyarn\nyarn start ${LANGUAGE}\n```\n\n(or)\n\n```console\nnpm install\nnpm run start ${LANGUAGE}\n```\n\nOpen `http://localhost:8080` in your browser to try the demo.\n\n### NodeJS Demos\n\nInstall the demo package:\n\n```console\nyarn global add @picovoice/porcupine-node-demo\n```\n\nWith a working microphone connected to your device run the following in the terminal:\n\n```console\nppn-mic-demo --access_key ${ACCESS_KEY} --keywords porcupine\n```\n\nThe engine starts processing the audio input from the microphone in realtime and outputs to the terminal when it detects\nutterances of `Porcupine`.\n\nFor more information about NodeJS demos go to [demo/nodejs](demo/nodejs).\n\n### Rust Demos\n\nThis demo opens an audio stream from a microphone and detects utterances of a given wake word.\nFrom [demo/rust/micdemo](demo/rust/micdemo) the following opens the default microphone and detects occurrences of \"Picovoice\":\n\n```console\ncargo run --release -- --access_key ${ACCESS_KEY} --keywords picovoice\n```\n\nFor more information about Rust demos go to [demo/rust](demo/rust).\n\n### C Demos\n\nThe C demo requires [CMake](https://cmake.org/) version 3.4 or higher.\n\nThe [Microphone demo](demo/c/porcupine_demo_mic.c) requires  [miniaudio](https://github.com/mackron/miniaudio) for accessing microphone audio data.\n\n**Windows Requires [MinGW](http://mingw-w64.org) to build the demo.**\n\n#### Microphone Demo\n\nAt the root of the repository, build with:\n\n```console\ncmake -S demo/c/. -B demo/c/build \u0026\u0026 cmake --build demo/c/build --target porcupine_demo_mic\n```\n\n#### Linux (x86_64), macOS (x86_64), Raspberry Pi, BeagleBone, and Jetson\n\nList input audio devices with:\n\n```console\n./demo/c/build/porcupine_demo_mic --show_audio_devices\n```\n\nRun the demo using:\n\n```console\n./demo/c/build/porcupine_demo_mic -l ${LIBRARY_PATH} -m lib/common/porcupine_params.pv \\\n-k resources/keyword_files/${PLATFORM}/porcupine_${PLATFORM}.ppn -t 0.5 \\\n-d ${AUDIO_DEVICE_INDEX} -a ${ACCESS_KEY}\n```\n\nReplace `${LIBRARY_PATH}` with path to appropriate library available under [lib](lib), `${PLATFORM}` with the\nname of the platform you are running on (`linux`, `raspberry-pi`, `mac`, `beaglebone`, or `jetson`), `${AUDIO_DEVICE_INDEX}` with\nthe index of your audio device and `${ACCESS_KEY}` with your `AccessKey`.\n\n#### Windows\n\nList input audio devices with:\n\n```console\n.\\\\demo\\\\c\\\\build\\\\porcupine_demo_mic.exe --show_audio_devices\n```\n\nRun the demo using:\n\n```console\n.\\\\demo\\\\c\\\\build\\\\porcupine_demo_mic.exe ^\n-l lib/windows/amd64/libpv_porcupine.dll ^\n-m lib/common/porcupine_params.pv ^\n-k resources/keyword_files/windows/porcupine_windows.ppn ^\n-t 0.5 ^\n-d ${AUDIO_DEVICE_INDEX} ^\n-a ${ACCESS_KEY}\n```\n\nReplace `${AUDIO_DEVICE_INDEX}` with the index of your audio device and `${ACCESS_KEY}` with your `AccessKey`.\n\nThe demo opens an audio stream and detects utterances of `Porcupine`.\n\n#### File Demo\n\nAt the root of the repository, build with:\n\n```console\ncmake -S demo/c/. -B demo/c/build \u0026\u0026 cmake --build demo/c/build --target porcupine_demo_file\n```\n\n#### Linux (x86_64), macOS (x86_64), Raspberry Pi, BeagleBone, and Jetson\n\nRun the demo using:\n\n```console\n./demo/c/build/porcupine_demo_file -l ${LIBRARY_PATH} -m lib/common/porcupine_params.pv \\\n-k resources/keyword_files/${PLATFORM}/porcupine_${PLATFORM}.ppn -t 0.5 \\\n-w resources/audio_samples/multiple_keywords.wav -a ${ACCESS_KEY}\n```\n\nReplace `${LIBRARY_PATH}` with path to appropriate library available under [lib](lib), `${PLATFORM}` with the\nname of the platform you are running on (`linux`, `raspberry-pi`, `mac`, `beaglebone`, or `jetson`) and `${ACCESS_KEY}` with your `AccessKey`.\n\n#### Windows\n\nRun the demo using:\n\n```console\n.\\\\demo\\\\c\\\\build\\\\porcupine_demo_file.exe ^\n-l lib/windows/amd64/libpv_porcupine.dll ^\n-m lib/common/porcupine_params.pv ^\n-k resources/keyword_files/windows/porcupine_windows.ppn ^\n-t 0.5 ^\n-w resources/audio_samples/multiple_keywords.wav ^\n-a ${ACCESS_KEY}\n```\n\nReplace `${ACCESS_KEY}` with your `AccessKey`.\n\nThe demo opens up the file and detects utterances of `Porcupine`.\n\nFor more information about C demos go to [demo/c](demo/c).\n\n### Microcontroller Demos\n\nThere are several projects for various development boards inside the [mcu demo](demo/mcu) folder.\n\n## SDKs\n\n### Python\n\nInstall the Python SDK:\n\n```console\npip3 install pvporcupine\n```\n\nThe SDK exposes a factory method to create instances of the engine:\n\n```python\nimport pvporcupine\n\n# AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\naccess_key = \"${ACCESS_KEY}\"\n\nhandle = pvporcupine.create(access_key=access_key, keywords=['picovoice', 'bumblebee'])\n```\n\n`keywords` argument is a shorthand for accessing default keyword files shipped with the library. The default keyword\nfiles available can be retrieved via\n\n```python\nimport pvporcupine\n\nprint(pvporcupine.KEYWORDS)\n```\n\nIf you wish to use a non-default keyword file you need to identify its path:\n\n```python\nimport pvporcupine\n\n# AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\naccess_key = \"${ACCESS_KEY}\"\n\nhandle = pvporcupine.create(\n    access_key=access_key,\n    keyword_paths=['path/to/non/default/keyword/file'])\n```\n\nWhen initialized, valid sample rate can be obtained using `handle.sample_rate`. The required frame length\n(number of audio samples in an input array) is `handle.frame_length`. The object can be used to monitor\nincoming audio as follows:\n\n```python\nimport pvporcupine\n\n# AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\naccess_key = \"${ACCESS_KEY}\"\n\nhandle = pvporcupine.create(access_key=access_key, keywords=['porcupine'])\n\ndef get_next_audio_frame():\n    pass\n\nwhile True:\n    keyword_index = handle.process(get_next_audio_frame())\n    if keyword_index \u003e= 0:\n        # Insert detection event callback here\n        pass\n```\n\nFinally, when done be sure to explicitly release the resources using `handle.delete()`.\n\n### .NET\n\nInstall the .NET SDK using NuGet or the dotnet CLI:\n\n```console\ndotnet add package Porcupine\n```\n\nThe SDK exposes a factory method to create instances of the engine:\n\n```csharp\nusing Pv;\n\nconst string accessKey = \"${ACCESS_KEY}\";\nvar keyword = new List\u003cBuiltInKeyword\u003e { BuiltInKeyword.PICOVOICE };\n\nPorcupine handle = Porcupine.FromBuiltInKeywords(accessKey, keyword);\n```\n\nUsing 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.\n\nIf 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:\n\n```csharp\nconst string accessKey = \"${ACCESS_KEY}\";\nvar keywordPaths = new List\u003cstring\u003e {\n    \"/absolute/path/to/keyword/one\",\n    \"/absolute/path/to/keyword/two\",\n    ... }\n\nPorcupine handle = Porcupine.FromKeywordPaths(accessKey, keywordPaths);\n```\n\nWhen initialized, the required sample rate can be obtained using `handle.SampleRate`. Expected frame length\n(number of audio samples in an input array) is `handle.FrameLength`. The object can be used to monitor\nincoming audio as below:\n\n```csharp\nshort[] getNextAudioFrame()\n{\n    // .. get a frame of audio\n    return audioFrame;\n}\n\nwhile(true)\n{\n    var keywordIndex = handle.Process(getNextAudioFrame())\n    if(keywordIndex \u003e= 0)\n    {\n        // .. Insert detection event callback here\n    }\n}\n```\n\nPorcupine will have its resources freed by the garbage collector, but to have resources freed immediately after use,\nwrap it in a `using` statement:\n\n```csharp\nusing(Porcupine handle = Porcupine.FromBuiltInKeywords(\n    accessKey,\n    new List\u003cBuiltInKeyword\u003e { BuiltInKeyword.PICOVOICE }))\n{\n    // .. Porcupine usage here\n}\n```\n\n### Java\n\nThe Porcupine Java binding is available from the Maven Central Repository at `ai.picovoice:porcupine-java:${version}`.\n\n\n```java\nimport ai.picovoice.porcupine.*;\n\n// AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nfinal String accessKey = \"${ACCESS_KEY}\";\ntry {\n    Porcupine handle = new Porcupine.Builder()\n                        .setAccessKey(accessKey)\n                        .setBuiltInKeyword(BuiltInKeyword.PORCUPINE)\n                        .build();\n} catch (PorcupineException e) { }\n```\n\nThe `setBuiltInKeyword()` builder argument is a shorthand for accessing built-in keyword model files shipped with the package.\n\nThe list of built-in keywords can be found in the `BuiltInKeyword` enum, and can be retrieved by:\n\n```java\nimport ai.picovoice.porcupine.*;\n\nfor(BuiltInKeyword keyword : BuiltInKeyword.values()) {\n    System.out.println(keyword.name());\n}\n```\n\nIf 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:\n\n```java\nimport ai.picovoice.porcupine.*;\n\n// AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nfinal String accessKey = \"${ACCESS_KEY}\";\ntry {\n    Porcupine handle = new Porcupine.Builder()\n                        .setAccessKey(accessKey)\n                        .setKeywordPath(\"path/to/custom/keyword/file\")\n                        .build();\n} catch (PorcupineException e) { }\n```\n\nWhen initialized, valid sample rate can be obtained using `handle.getSampleRate()`. Expected frame length\n(number of audio samples in an input array) is `handle.getFrameLength()`. The object can be used to monitor\nincoming audio as below:\n\n```java\nshort[] getNextAudioFrame() {\n    // .. get audioFrame\n    return audioFrame;\n}\n\nwhile(true) {\n    int keywordIndex = handle.Process(getNextAudioFrame());\n    if(keywordIndex \u003e= 0) {\n        // .. detection event logic/callback\n    }\n}\n```\n\nOnce you're done with Porcupine, ensure you release its resources explicitly:\n\n```java\nhandle.delete();\n```\n\n### Go\n\nTo install the Porcupine Go module to your project, use the command:\n```console\ngo get github.com/Picovoice/porcupine/binding/go\n```\n\nTo create an instance of the engine you first create a Porcupine struct with the configuration parameters for the wake word engine and then make a call to `.Init()`.\n\n```go\nimport . \"github.com/Picovoice/porcupine/binding/go/v2\"\n\nporcupine := Porcupine{\n  AccessKey: \"${ACCESS_KEY}\", // from Picovoice Console (https://console.picovoice.ai/)\n  BuiltInKeywords: []BuiltInKeyword{PICOVOICE}}\nerr := porcupine.Init()\nif err != nil {\n    // handle init fail\n}\n```\n\nIn the above example, we've initialized the engine to detect the built-in wake word \"Picovoice\". Built-in keywords are constants in the package with the BuiltInKeyword type.\n\nTo detect non-default keywords, use `KeywordPaths` parameter instead\n\n```go\nporcupine := Porcupine{\n  AccessKey: \"${ACCESS_KEY}\", // from Picovoice Console (https://console.picovoice.ai/)\n  KeywordPaths: []string{\"/path/to/keyword.ppn\"}}\nerr := porcupine.Init()\n```\n\nWhen initialized, the valid sample rate is given by `SampleRate`. Expected frame length (number of audio samples in an input array) is given by `FrameLength`. The engine accepts 16-bit linearly-encoded PCM and operates on single-channel audio.\n\nTo feed audio into Porcupine, use the `Process` function in your capture loop. You must call `Init()` before calling `Process`.\n```go\nfunc getNextFrameAudio() []int16 {\n    // get audio frame\n}\n\nfor {\n    keywordIndex, err := porcupine.Process(getNextFrameAudio())\n    if keywordIndex \u003e= 0 {\n        // wake word detected!\n    }\n}\n```\n\nWhen done resources have to be released explicitly.\n\n```go\nporcupine.Delete()\n```\n\n### Unity\n\nImport the [Porcupine Unity Package](binding/unity/porcupine-3.0.1.unitypackage) into your Unity project.\n\nThe SDK provides two APIs:\n\n#### High-Level API\n\n[PorcupineManager](binding/unity/Assets/Porcupine/PorcupineManager.cs) provides a high-level API that takes care of audio recording. This is the quickest way to get started.\n\nThe static constructor `PorcupineManager.FromBuiltInKeywords` will create an instance of the `PorcupineManager` using one or more of the built-in keywords.\n\n```csharp\nusing Pv.Unity;\n\n// AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nstring accessKey = \"${ACCESS_KEY}\";\n\ntry {\n    List\u003cPorcupine.BuiltInKeyword\u003e keywords = new List\u003cPorcupine.BuiltInKeyword\u003e(){\n        Porcupine.BuiltInKeyword.PICOVOICE,\n        Porcupine.BuiltInKeyword.PORCUPINE\n    };\n    PorcupineManager _porcupineManager = PorcupineManager.FromBuiltInKeywords(\n                                            accessKey,\n                                            keywords,\n                                            OnWakeWordDetected);\n}\ncatch (Exception ex)\n{\n    // handle porcupine init error\n}\n```\n\nTo create an instance of PorcupineManager that detects custom keywords, you can use the `PorcupineManager.FromKeywordPaths`\nstatic constructor and provide the paths to the `.ppn` file(s).\n\n```csharp\n// AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nstring accessKey = \"${ACCESS_KEY}\";\n\nList\u003cstring\u003e keywordPaths = new List\u003cstring\u003e(){ \"/path/to/keyword.ppn\" };\nPorcupineManager _porcupineManager = PorcupineManager.FromKeywordPaths(\n                                        accessKey,\n                                        keywordPaths,\n                                        OnWakeWordDetected);\n```\n\nOnce you have instantiated a PorcupineManager, you can start/stop audio capture and wake word detection by calling:\n\n```csharp\n_porcupineManager.Start();\n// .. use porcupine\n_porcupineManager.Stop();\n```\n\nOnce the app is done with using PorcupineManager, you can explicitly release the resources allocated to Porcupine:\n\n```csharp\n_porcupineManager.Delete();\n```\n\nThere is no need to deal with audio capture to enable wake word detection with PorcupineManager.\nThis is because it uses our\n[unity-voice-processor](https://github.com/Picovoice/unity-voice-processor/)\nUnity package to capture frames of audio and automatically pass it to the wake word engine.\n\n#### Low-Level API\n\n[Porcupine](binding/unity/Assets/Porcupine/Porcupine.cs) 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 create an instance of `Porcupine`, use the `.FromBuiltInKeywords` static constructor.\n\n```csharp\nusing Pv.Unity;\n\n// AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nstring accessKey = \"${ACCESS_KEY}\";\n\ntry\n{\n    List\u003cPorcupine.BuiltInKeyword\u003e keywords = new List\u003cPorcupine.BuiltInKeyword\u003e(){\n        Porcupine.BuiltInKeyword.PORCUPINE,\n        Porcupine.BuiltInKeyword.PICOVOICE\n    };\n    Porcupine _porcupine = Porcupine.FromBuiltInKeywords(\n        accessKey: accessKey,\n        keywords: keywords);\n}\ncatch (Exception ex)\n{\n    // handle porcupine init error\n}\n```\n\nTo 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.\n\n```csharp\nshort[] frame = getAudioFrame();\n\ntry\n{\n    int keywordIndex = _porcupine.Process(frame);\n    if (keywordIndex \u003e= 0)\n    {\n        // detection made!\n    }\n}\ncatch (Exception ex)\n{\n    Debug.LogError(ex.ToString());\n}\n```\n\nFor `Process` to work correctly, the provided audio must be single-channel and 16-bit linearly-encoded.\n\nFinally, once you no longer need the wake word engine, you can explicitly release the resources allocated to Porcupine:\n\n```csharp\n_porcupine.Dispose();\n```\n\n### Flutter\n\nAdd the [Porcupine Flutter plugin](https://pub.dev/packages/porcupine) to your pub.yaml.\n\n```yaml\ndependencies:\n  flutter_porcupine: ^\u003cversion\u003e\n```\n\nThe SDK provides two APIs:\n\n#### High-Level API\n\n[PorcupineManager](binding/flutter/lib/porcupine_manager.dart) provides a high-level API that takes care of audio recording. This class is the quickest way to get started.\n\nThe static constructor `PorcupineManager.fromBuiltInKeywords` will create an instance of the `PorcupineManager` using one or more of the built-in keywords.\n\n```dart\nimport 'package:porcupine_flutter/porcupine_manager.dart';\nimport 'package:porcupine_flutter/porcupine_error.dart';\n\n// AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nfinal String accessKey = \"{ACCESS_KEY}\";\n\nvoid createPorcupineManager() async {\n    try {\n        _porcupineManager = await PorcupineManager.fromBuiltInKeywords(\n            accessKey,\n            [BuiltInKeyword.PICOVOICE, BuiltInKeyword.PORCUPINE],\n            _wakeWordCallback);\n    } on PorcupineException catch (err) {\n        // handle porcupine init error\n    }\n}\n```\n\nTo 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).\n\n```dart\n // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nfinal String accessKey = \"{ACCESS_KEY}\";\n\n_porcupineManager = await PorcupineManager.fromKeywordPaths(\n    accessKey,\n    [\"/path/to/keyword.ppn\"],\n    _wakeWordCallback);\n```\n\nOnce you have instantiated a PorcupineManager, you can start/stop audio capture and wake word detection by calling:\n\n```dart\ntry {\n    await _porcupineManager.start();\n} on PorcupineException catch (ex) {\n    // deal with either audio exception\n}\n// .. use porcupine\nawait _porcupineManager.stop();\n```\n\nOnce the app is done with using PorcupineManager, be sure you explicitly release the resources allocated to Porcupine:\n\n```dart\nawait _porcupineManager.delete();\n```\n\nThere is no need to deal with audio capture to enable wake word detection with PorcupineManager.\nThis is because it uses [flutter_voice_processor](https://github.com/Picovoice/flutter-voice-processor/) plugin to capture frames of audio and automatically pass it to the wake word engine.\n\n#### Low-Level API\n\n[Porcupine](binding/flutter/lib/porcupine.dart) 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.\n\n```dart\nimport 'package:porcupine_flutter/porcupine_manager.dart';\nimport 'package:porcupine_flutter/porcupine_error.dart';\n\n// AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nfinal String accessKey = \"{ACCESS_KEY}\";\n\nvoid createPorcupine() async {\n    try {\n        _porcupine = await Porcupine.fromBuiltInKeywords(\n          accessKey,\n          [BuiltInKeyword.PICOVOICE]);\n    } on PorcupineException catch (err) {\n        // handle porcupine init error\n    }\n}\n```\n\nTo 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.\n\n```dart\nList\u003cint\u003e buffer = getAudioFrame();\n\ntry {\n    int keywordIndex = _porcupine.process(buffer);\n    if (keywordIndex \u003e= 0) {\n        // detection made!\n    }\n} on PorcupineException catch (error) {\n    // handle error\n}\n```\n\nFor `process` to work correctly, the provided audio must be single-channel and 16-bit linearly-encoded.\n\nFinally, once you no longer need the wake word engine, be sure to explicitly release the resources allocated to Porcupine:\n\n```dart\n_porcupine.delete();\n```\n\n### React Native\n\nInstall [@picovoice/react-native-voice-processor](https://www.npmjs.com/package/@picovoice/react-native-voice-processor)\nand [@picovoice/porcupine-react-native](https://www.npmjs.com/package/@picovoice/porcupine-react-native). The SDK\nprovides two APIs:\n\n#### High-Level API\n\n[PorcupineManager](binding/react-native/src/porcupine_manager.tsx) provides a high-level API that takes care of\naudio recording. This class is the quickest way to get started.\n\nUsing the constructor `PorcupineManager.fromBuiltInKeywords` will create an instance of the `PorcupineManager`\nusing one or more of the built-in keywords.\n\n```javascript\n // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nconst accessKey = \"${ACCESS_KEY}\";\n\nasync createPorcupineManager(){\n    try {\n        this._porcupineManager = await PorcupineManager.fromBuiltInKeywords(\n            accessKey,\n            [BuiltInKeywords.Picovoice, BuiltInKeywords.Porcupine],\n            detectionCallback,\n            processErrorCallback);\n    } catch (err) {\n        // handle error\n    }\n}\n```\n\nTo create an instance of PorcupineManager that detects custom keywords, you can use the `PorcupineManager.fromKeywordPaths`\nstatic constructor and provide the paths to the `.ppn` file(s).\n\n```javascript\n// AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nconst accessKey = \"${ACCESS_KEY}\";\n\nthis._porcupineManager = await PorcupineManager.fromKeywordPaths(\n  accessKey,\n  [\"/path/to/keyword.ppn\"],\n  detectionCallback,\n  processErrorCallback\n);\n```\n\nOnce you have instantiated a Porcupine manager, you can start/stop audio capture and wake word detection by calling:\n\n```javascript\nlet didStart = this._porcupineManager.start();\n// .. use Porcupine\nlet didStop = this._porcupineManager.stop();\n```\n\nOnce the app is done with using PorcupineManager, be sure you explicitly release the resources allocated to Porcupine:\n\n```javascript\nthis._porcupineManager.delete();\n```\n\nThere is no need to deal with audio capture to enable wake word detection with PorcupineManager.\nThis is because it uses [@picovoice/react-native-voice-processor](https://github.com/Picovoice/react-native-voice-processor/)\nmodule to capture frames of audio and automatically pass it to the wake word engine.\n\n#### Low-Level API\n\n[Porcupine](binding/react-native/src/porcupine.tsx) provides low-level access to the wake word engine for those\nwho want to incorporate wake word detection into an already existing audio processing pipeline. `Porcupine` also has\n`fromBuiltInKeywords` and `fromKeywordPaths` static constructors.\n\n```javascript\n// AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nconst accessKey = \"${ACCESS_KEY}\";\n\nasync createPorcupine(){\n    try {\n        this._porcupine = await Porcupine.fromBuiltInKeywords(\n            accessKey, [BuiltInKeywords.PICOVOICE]);\n    } catch (err) {\n        // handle error\n    }\n}\n```\n\nTo 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.\n\n```javascript\nlet buffer = getAudioFrame();\n\ntry {\n  let keywordIndex = await this._porcupine.process(buffer);\n  if (keywordIndex \u003e= 0) {\n    // detection made!\n  }\n} catch (e) {\n  // handle error\n}\n```\n\nFor `process` to work correctly, the provided audio must be single-channel and 16-bit linearly-encoded.\n\nFinally, once you no longer need the wake word engine, be sure to explicitly release the resources allocated to Porcupine:\n\n```javascript\nthis._porcupine.delete();\n```\n\n### Android\n\nTo 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`:\n\n```groovy\ndependencies {\n    implementation 'ai.picovoice:porcupine-android:${LATEST_VERSION}'\n}\n```\n\nThere are two possibilities for integrating Porcupine into an Android application.\n\n#### High-Level API\n\n[PorcupineManager](binding/android/Porcupine/porcupine/src/main/java/ai/picovoice/porcupine/PorcupineManager.java)\nprovides a high-level API for integrating Porcupine into Android applications. It manages all activities related to creating\nan input audio stream, feeding it into the Porcupine library, and invoking a user-provided detection callback.\n\n```java\nimport ai.picovoice.porcupine.*;\n\nfinal String accessKey = \"${ACCESS_KEY}\"; // AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nfinal String keywordPath = \"/path/to/keyword.ppn\"; // path relative to 'assets' folder\n\ntry {\n    PorcupineManager porcupineManager = new PorcupineManager.Builder()\n                        .setAccessKey(accessKey)\n                        .setKeywordPath(keywordPath)\n                        .setSensitivity(0.5f)\n                        .build(context,\n                        new PorcupineManagerCallback() {\n                            @Override\n                            public void invoke(int keywordIndex) {\n                                // detection event logic/callback\n                            }\n                        });\n} catch (PorcupineException e) { }\n```\nKeyword files (`.ppn`) should be placed under the Android project assets folder (`src/main/assets/`).\n\nSensitivity is the parameter that enables developers to trade miss rate for false alarm. It is a floating point number within\n[0, 1]. A higher sensitivity reduces miss rate at cost of increased false alarm rate.\n\nWhen initialized, input audio can be monitored using `manager.start()`. Stop the manager using by invoking\n`manager.stop()`. When done be sure to release the resources using `manager.delete()`.\n\n#### Low-Level API\n\n[Porcupine](binding/android/Porcupine/porcupine/src/main/java/ai/picovoice/porcupine/Porcupine.java) provides a\nbinding for Android. It can be initialized using:\n\n```java\nimport ai.picovoice.porcupine.*;\n\nfinal String accessKey = \"${ACCESS_KEY}\";\nfinal String keywordPath = \"/path/to/keyword.ppn\";\ntry {\n    Porcupine porcupine = new Porcupine.Builder()\n                        .setAccessKey(accessKey)\n                        .setKeywordPath(keywordPath)\n                        .setSensitivity(0.5f)\n                        .build(context);\n} catch (PorcupineException e) { }\n```\nOnce initialized, `porcupine` can be used to monitor incoming audio.\n\n```java\nprivate short[] getNextAudioFrame();\n\nwhile (true) {\n    final int keywordIndex = porcupine.process(getNextAudioFrame());\n    if (keywordIndex != -1) {\n        // detection event logic/callback\n    }\n}\n```\n\nFinally, be sure to explicitly release resources acquired by porcupine as the binding class does not rely on the garbage collector for releasing native resources.\n\n```java\nporcupine.delete();\n```\n\n### iOS\n\nThere are two approaches for integrating Porcupine into an iOS application.\n\n#### High-Level API\n\n[PorcupineManager](binding/ios/PorcupineManager.swift) manages audio recording, passing it into Porcupine, and invoking\nthe user-provided detection callback.\n\n```swift\nlet accessKey = \"${ACCESS_KEY}\" // Obtained from Picovoice Console (https://console.picovoice.ai)\nlet modelPath: String = ... // Available at lib/common/porcupine_params.pv\nlet keywordPaths: [String] = [\"/path/to/keyword/file/a\", \"/path/to/keyword/file/b\"]\nlet sensitivities: [Float32] = [0.35, 0.64]\nlet keywordCallback: ((Int32) -\u003e Void) = { keywordIndex in\n    // Insert detection event logic\n}\n\nlet manager = try PorcupineManager(\n    accessKey: accessKey,\n    modelPath: modelPath,\n    keywordPaths: keywordPaths,\n    sensitivities: sensitivities\n    onDetection: keywordCallback)\n```\n\nWhen initialized, input audio can be monitored using `manager.start()`. When done be sure to stop the manager using\n`manager.stop()`.\n\n#### Low-Level API\n\n[Porcupine.swift](binding/ios/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.\n\nTo construct an instance of Porcupine, pass it a keyword.\n\n```swift\nimport Porcupine\n\nlet accessKey = \"${ACCESS_KEY}\" // Obtained from Picovoice Console (https://console.picovoice.ai)\n\ndo {\n    Porcupine porcupine = try Porcupine(\n      accessKey: accessKey,\n      keyword: Porcupine.BuiltInKeyword.picovoice)\n} catch { }\n```\n\nTo 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.\n\n```swift\nfunc getNextAudioFrame() -\u003e [Int16] {\n    // .. get audioFrame\n    return audioFrame;\n}\n\nwhile true {\n    do {\n        let keywordIndex = try porcupine.process(getNextAudioFrame())\n        if keywordIndex \u003e= 0 {\n            // .. detection made!\n        }\n    } catch { }\n}\n```\n\nOnce you're done with Porcupine you can force it to release its native resources rather than waiting for the garbage collector:\n```swift\nporcupine.delete();\n```\n\n### Web\n\nPorcupine is available on modern web browsers (i.e. not Internet Explorer) via [WebAssembly](https://webassembly.org/). Microphone audio is handled via the [Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/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](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers).\n\nEach spoken language is available as a dedicated npm package (e.g. @picovoice/porcupine-web-en-worker). These packages can be used with the @picovoice/web-voice-processor. They can also be used with the Angular, React, and Vue bindings, which abstract and hide the web worker communication details.\n\n#### Vanilla JavaScript and HTML (CDN Script Tag)\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n  \u003cscript src=\"https://unpkg.com/@picovoice/porcupine-web/dist/iife/index.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://unpkg.com/@picovoice/web-voice-processor/dist/iife/index.js\"\u003e\u003c/script\u003e\n  \u003cscript type=\"application/javascript\"\u003e\n\n    const PORCUPINE_MODEL_BASE64 = /* Base64 representation of the `.pv` model file*/;\n\n    function keywordDetectionCallback(detection) {\n      console.log(`Porcupine detected ${detection.label}`);\n    }\n\n    function processErrorCallback(error) {\n      console.error(error);\n    }\n\n    async function startPorcupine() {\n      console.log(\"Porcupine is loading. Please wait...\");\n      const accessKey = \"${ACCESS_KEY}\" // Obtained from Picovoice Console (picovoice.ai/console/)\n      let porcupine = await PorcupineWeb.PorcupineWorker.create(\n              accessKey,\n              [PorcupineWeb.BuiltInKeyword.Picovoice],\n              porcupineKeywordCallback,\n              { base64: PORCUPINE_MODEL_BASE64 },\n      );\n\n      console.log(\"Porcupine worker ready!\");\n\n      console.log(\"WebVoiceProcessor initializing. Microphone permissions requested ...\");\n      await window.WebVoiceProcessor.WebVoiceProcessor.subscribe(porcupine);\n      console.log(\"WebVoiceProcessor ready and listening!\");\n\n      document.addEventListener(\"DOMContentLoaded\", function () {\n        startPorcupine();\n      });\n  \u003c/script\u003e\n\u003c/head\u003e\n\u003cbody\u003e\u003c/body\u003e\n\u003c/html\u003e\n```\n\n#### Vanilla JavaScript and HTML (ES Modules)\n\nInstall the web SDK using yarn:\n\n```console\nyarn add @picovoice/porcupine-web @picovoice/web-voice-processor\n```\n\n(or)\n\n```console\nnpm install --save @picovoice/porcupine-web @picovoice/web-voice-processor\n```\n\n```javascript\nimport { WebVoiceProcessor } from \"@picovoice/web-voice-processor\"\nimport { PorcupineWorker } from \"@picovoice/porcupine-web\";\n\nconst PORCUPINE_MODEL_BASE64 = /* Base64 representation of the `.pv` model file*/;\n\nfunction keywordDetectionCallback(detection) {\n  console.log(`Porcupine detected ${detection.label}`);\n}\n\nconst porcupine = await PorcupineWorker.create(\n  \"${ACCESS_KEY}\",\n  PorcupineWeb.BuiltInKeyword.Porcupine,\n  keywordDetectionCallback,\n  { base64: PORCUPINE_MODEL_BASE64 },\n);\n\nconsole.log(\"WebVoiceProcessor initializing. Microphone permissions requested ...\");\nawait WebVoiceProcessor.subscribe(porcupine);\nconsole.log(\"WebVoiceProcessor ready and listening!\");\n\n...\n\n// Finished with Porcupine? Release the WebVoiceProcessor and the worker.\nif (done) {\n  await WebVoiceProcessor.unsubscribe(porcupine);\n  porcupine.release()\n  porcupine.terminate()\n}\n```\n\n#### Angular\n\n```console\nyarn add @picovoice/porcupine-angular @picovoice/web-voice-processor\n```\n\n(or)\n\n```console\nnpm install @picovoice/porcupine-angular @picovoice/web-voice-processor\n```\n\n```typescript\nimport { Subscription } from \"rxjs\";\nimport { PorcupineService } from \"@picovoice/porcupine-web-angular\";\nimport {BuiltInKeyword} from '@picovoice/porcupine-web';\nimport porcupineParams from \"${PATH_TO_PORCUPINE_PARAMS_BASE64}\";\n\nconstructor(private porcupineService: PorcupineService) {\n  this.keywordSubscription = porcupineService.keyword$.subscribe(\n    porcupineDetection =\u003e {\n      console.log(`Porcupine Detected \"${porcupineDetection.label}\"`)\n    });\n  this.isLoadedSubscription = porcupineService.isLoaded$.subscribe(\n    isLoaded =\u003e {\n      console.log(isLoaded);\n    });\n  this.isListeningSubscription = porcupineService.isListening$.subscribe(\n    isListening =\u003e {\n      console.log(isListening);\n    });\n  this.errorSubscription = porcupineService.error$.subscribe(\n    error =\u003e {\n      console.error(error);\n    });\n}\n\nasync ngOnInit() {\n  await this.porcupineService.init(\n    ${ACCESS_KEY},\n    [BuiltInKeyword.Porcupine],\n    porcupineModel,\n    options\n  ).then(() =\u003e {\n    this.porcupineService.start();\n  });\n}\n\nngOnDestroy() {\n  this.keywordSubscription.unsubscribe();\n  this.isLoadedSubscription.unsubscribe();\n  this.isListeningSubscription.unsubscribe();\n  this.errorSubscription.unsubscribe();\n  this.porcupineService.release();\n}\n```\n\n#### React\n\n```console\nyarn add @picovoice/porcupine-react @picovoice/web-voice-processor\n```\n\n(or)\n\n```console\nnpm install @picovoice/porcupine-react @picovoice/web-voice-processor\n```\n\n```javascript\nimport { BuiltInKeyword } from '@picovoice/porcupine-web';\nimport { usePorcupine } from '@picovoice/porcupine-react';\n\nfunction App(props) {\n  const {\n    wakeWordDetection,\n    isLoaded,\n    isListening,\n    error,\n    init,\n    start,\n    stop,\n    release,\n  } = usePorcupine();\n\n  const initEngine = async () =\u003e {\n    await init(\n      ${ACCESS_KEY},\n      [BuiltInKeyword.Porcupine],\n      porcupineModel\n    );\n    await start();\n  }\n\n  useEffect(() =\u003e {\n    if (wakeWordDetection !== null) {\n      console.log(wakeWordDetection.label);\n    }\n  }, [wakeWordDetection])\n}\n```\n\n#### Vue\n\n```console\nyarn add @picovoice/porcupine-vue @picovoice/web-voice-processor\n```\n\n(or)\n\n```console\nnpm install @picovoice/porcupine-vue @picovoice/web-voice-processor\n```\n\n```vue\n\u003cscript lang='ts'\u003e\nimport { BuiltInKeyword } from '@picovoice/porcupine-web';\nimport { usePorcupine } from '@picovoice/porcupine-vue';\n\nimport porcupineParams from \"${PATH_TO_PORCUPINE_PARAMS_BASE64}\"\n\n// Use Vue.extend for JavaScript\nexport default {\n  data() {\n    const {\n      state,\n      init,\n      start,\n      stop,\n      release\n    } = usePorcupine();\n\n    init(\n      ${ACCESS_KEY},\n      [BuiltInKeyword.Porcupine],\n      { base64: porcupineParams }, // porcupine model\n    );\n\n    return {\n      state,\n      start,\n      stop,\n      release\n    }\n  },\n  watch: {\n    \"state.keywordDetection\": function (keyword) {\n      if (keyword !== null) {\n        console.log(keyword.label);\n      }\n    },\n    \"state.isLoaded\": function (isLoaded) {\n      console.log(isLoaded)\n    },\n    \"state.isListening\": function (isListening) {\n      console.log(isListening)\n    },\n    \"state.error\": function (error) {\n      console.error(error)\n    },\n  },\n  onBeforeDestroy() {\n    this.release();\n  },\n};\n\u003c/script\u003e\n```\n\n### NodeJS\n\nInstall NodeJS SDK:\n\n```console\nyarn add @picovoice/porcupine-node\n```\n\nCreate instances of the Porcupine class by specifying which keywords you want it to listen for:\n\n```javascript\nconst {\n  Porcupine,\n  BuiltinKeyword,\n}= require(\"@picovoice/porcupine-node\");\n\n // Obtained from the Picovoice Console (https://console.picovoice.ai/)\nconst accessKey = \"${ACCESS_KEY}\";\n\nlet handle = new Porcupine(\n    accessKey,\n    [BuiltinKeyword.GRASSHOPPER, BuiltinKeyword.BUMBLEBEE],\n    [0.5, 0.65]);\n```\n\n`GRASSHOPPER` and `BUMBLEBEE` are built-in keywords. If you wish to use a custom keyword file, you need to identify its path:\n\n```javascript\nconst Porcupine = require(\"@picovoice/porcupine-node\");\n\n // Obtained from the Picovoice Console (https://console.picovoice.ai/)\nconst accessKey = \"${ACCESS_KEY}\";\n\nlet handle = new Porcupine(\n    accessKey,\n    [\"/path/to/custom/keyword/file\"],\n    [0.5]);\n```\n\nWhen instantiated, `handle` can process audio via its `.process` method.\n\n```javascript\nlet getNextAudioFrame = function() {\n    ...\n};\n\nwhile (true) {\n  let keywordIndex = handle.process(getNextAudioFrame());\n  if (keywordIndex !== -1) {\n    // detection event callback\n  }\n}\n```\n\nWhen done be sure to release resources acquired by WebAssembly using `release()`:\n\n```javascript\nhandle.release();\n```\n\n### Rust\n\nFirst you will need [Rust and Cargo](https://rustup.rs/) installed on your system.\n\nTo add the porcupine library into your app, add `pv_porcupine` to your apps `Cargo.toml` manifest:\n```toml\n[dependencies]\npv_porcupine = \"*\"\n```\n\nTo create an instance of the engine you first create a `PorcupineBuilder` instance with the configuration parameters for the wake word engine and then make a call to `.init()`:\n\n```rust\nuse porcupine::{BuiltinKeywords, PorcupineBuilder};\n\n// AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nlet access_key = \"${ACCESS_KEY}\";\n\nlet porcupine: Porcupine = PorcupineBuilder::new_with_keywords(\n        access_key,\n        \u0026[BuiltinKeywords::Porcupine]\n    )\n    .init()\n    .expect(\"Unable to create Porcupine\");\n```\nIn the above example, we've initialized the engine to detect the built-in wake word \"Porcupine\".\nBuilt-in keywords are contained in the package with the `BuiltinKeywords` enum type.\n\nTo detect custom keywords, use `PorcupineBuilder`'s `new_with_keyword_paths` method to pass in `*.ppn` file paths instead:\n```rust\nlet porcupine: Porcupine = PorcupineBuilder::new_with_keyword_paths(\n        \u0026[\"/absolute/path/to/keyword/one.ppn\",\n        \"/absolute/path/to/keyword/two.ppn\"]\n    )\n    .init()\n    .expect(\"Unable to create Porcupine\");\n```\n\nWhen initialized, the valid sample rate is given by `sample_rate()`.\nExpected frame length (number of audio samples in an input array) is given by `frame_length()`.\nThe engine accepts 16-bit linearly-encoded PCM and operates on single-channel audio.\n\nTo feed audio into Porcupine, use the `process` function in your capture loop:\n```rust\nfn next_audio_frame() -\u003e Vec\u003ci16\u003e {\n    // get audio frame\n}\n\nloop {\n    if let Ok(keyword_index) = porcupine.process(\u0026next_audio_frame()) {\n        if keyword_index \u003e= 0 {\n            // wake word detected!\n        }\n    }\n}\n```\n\n### C\n\nPorcupine is implemented in ANSI C and therefore can be directly linked to C applications.\n[include/pv_porcupine.h](include/pv_porcupine.h) header file contains relevant information. An instance of Porcupine\nobject can be constructed as follows.\n\n```c\n// Available at lib/common/porcupine_params.pv\nconst char *model_path = ...\n// AccessKey obtained from Picovoice Console (https://console.picovoice.ai/)\nconst char *access_key = ...\nconst char *keyword_path = ...\nconst float sensitivity = 0.5f;\n\npv_porcupine_t *handle = NULL;\nconst pv_status_t status = pv_porcupine_init(\n    access_key,\n    model_path,\n    1,\n    \u0026keyword_path,\n    \u0026sensitivity,\n    \u0026handle);\nif (status != PV_STATUS_SUCCESS) {\n    // Insert error handling logic\n}\n```\n\nSensitivity is the parameter that enables developers to trade miss rate for false alarm. It is a floating point number\nwithin [0, 1]. A higher sensitivity reduces miss rate (false reject rate) at cost of (potentially) increased false alarm\nrate.\n\nNow the `handle` can be used to monitor incoming audio stream. Porcupine accepts single channel, 16-bit linearly-encoded\nPCM audio. The sample rate can be retrieved using `pv_sample_rate()`. Finally, Porcupine accepts input audio in\nconsecutive chunks (aka frames) the length of each frame can be retrieved using `pv_porcupine_frame_length()`.\n\n```c\nextern const int16_t *get_next_audio_frame(void);\n\nwhile (true) {\n    const int16_t *pcm = get_next_audio_frame();\n    int32_t keyword_index = -1;\n    const pv_status_t status = pv_porcupine_process(handle, pcm, \u0026keyword_index);\n    if (status != PV_STATUS_SUCCESS) {\n        // error handling logic\n    }\n    if (keyword_index != -1) {\n        // Insert detection event callback\n    }\n}\n```\n\nFinally, when done be sure to release the acquired resources:\n\n```c\npv_porcupine_delete(handle);\n```\n\n### Microcontroller\n\nPorcupine 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.\n\n```c\n#define MEMORY_BUFFER_SIZE ...\nuint8_t memory_buffer[MEMORY_BUFFER_SIZE] __attribute__((aligned(16)));\n\n// AccessKey string obtained from Picovoice Console (https://console.picovoice.ai/)\nstatic const char* ACCESS_KEY = ...\n\nconst uint8_t keyword_array[] = {...};\n\nconst int32_t keyword_model_sizes = sizeof(keyword_array);\nconst void *keyword_models = keyword_array;\nconst float sensitivity = 0.5f;\n\npv_porcupine_t *handle = NULL;\n\nconst pv_status_t status = pv_porcupine_init(\n        ACCESS_KEY,\n        MEMORY_BUFFER_SIZE,\n        memory_buffer,\n        1,\n        \u0026keyword_model_sizes,\n        \u0026keyword_models,\n        \u0026sensitivity,\n        \u0026handle);\n\nif (status != PV_STATUS_SUCCESS) {\n    // error handling logic\n}\n```\n\nSensitivity is the parameter that enables developers to trade miss rate for false alarm. It is a floating-point number\nwithin [0, 1]. A higher sensitivity reduces miss rate (false reject rate) at cost of increased false alarm rate.\n\nNow the `handle` can be used to monitor incoming audio stream. Porcupine accepts single channel, 16-bit PCM audio. The\nsample rate can be retrieved using `pv_sample_rate()`. Finally, Picovoice accepts input audio in consecutive chunks (aka\nframes) the length of each frame can be retrieved using `pv_porcupine_frame_length()`.\n\n```c\nextern const int16_t *get_next_audio_frame(void);\n\nwhile (true) {\n    const int16_t *pcm = get_next_audio_frame();\n    int32_t keyword_index;\n    const pv_status_t status = pv_porcupine_process(handle, pcm, \u0026keyword_index);\n    if (status != PV_STATUS_SUCCESS) {\n        // error handling logic\n    }\n    if (keyword_index != -1) {\n        // detection event logic/callback\n    }\n}\n```\n\nFinally, when done be sure to release the acquired resources.\n\n```c\npv_porcupine_delete(handle);\n```\n\n## Releases\n\n### v3.0.0 - October 26th, 2023\n\n- Improvements to error reporting\n- Upgrades to authorization and authentication system\n- Various bug fixes and improvements\n- Added Farsi support for microcontrollers\n- Node min support bumped to 16\n- Unity editor min support bumped to 2021\n- Patches to .NET support\n\n### v2.2.0 - April 12th, 2023\n\n- Added language support for Arabic, Dutch, Hindi, Mandarin, Polish, Russian, Swedish and Vietnamese\n- Added support for .NET 7.0 and fixed support for .NET Standard 2.0\n- iOS minimum support moved to 11.0\n- Improved stability and performance\n\n### v2.1.0 - January 20th, 2022\n\n- Added macOS arm64 (Apple Silicon) support for Java and Unity SDKs\n- Various bug fixes and improvements\n\n### v2.0.0 - Nov 25th, 2021\n\n- Improved accuracy\n- Added Rust SDK\n- macOS arm64 support\n- Added NodeJS support for Windows, NVIDIA Jetson Nano, and BeagleBone\n- Added .NET support for NVIDIA Jetson Nano and BeagleBone\n- Runtime optimization\n\n### v1.9.0 - December 2nd, 2020\n\n- Added React Native SDK\n- Added Java SDK\n- Added .NET SDK\n- Added NodeJS SDK\n- Improved accuracy\n- Runtime optimization\n\n### v1.8.0 - May 27th, 2020\n\n- Improved accuracy\n- Runtime optimization\n\n### v1.7.0 - Feb 13th, 2020\n\n- Improved accuracy\n- Runtime optimization\n- Added support for Raspberry Pi 4\n- Added service-based Android demo application\n- Added C demo applications\n- Updated documentation\n\n### v1.6.0 - April 25th, 2019\n\n- Improved accuracy\n- Runtime optimization\n- Added support for BeagleBone\n- iOS build can run on simulator now\n\n### v1.5.0 - November 13, 2018\n\n- Improved accuracy\n- Runtime optimization\n- Added support for running within web browsers (WebAssembly)\n\n### v1.4.0 - July 20, 2018\n\n- Improved accuracy\n- Runtime optimizations.\n- Updated documentation\n\n### v1.3.0 - June 19, 2018\n\n- Improved accuracy\n- Runtime optimizations\n\n### v1.2.0 - April 21, 2018\n\n- Runtime optimizations\n\n### v1.1.0 - April 11, 2018\n\n- Added multiple command detection capability\n\n### v1.0.0 - March 13, 2018\n\n- Initial release\n\n## FAQ\n\nYou can find the FAQ [here](https://picovoice.ai/docs/faq/porcupine/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPicovoice%2FPorcupine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPicovoice%2FPorcupine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPicovoice%2FPorcupine/lists"}