Skip to content

Commit

Permalink
V1.5 (#121)
Browse files Browse the repository at this point in the history
v1.5

Former-commit-id: 85560f8
  • Loading branch information
kenarsa authored Nov 14, 2018
1 parent 9a7f25a commit 8124a42
Show file tree
Hide file tree
Showing 340 changed files with 373 additions and 300 deletions.
53 changes: 32 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
# Porcupine   [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=On-device%20wake%20word%20detection%20engine%20powered%20by%20deep%20learning&url=https://github.com/Picovoice/Porcupine&hashtags=deeplearning,voice,AI,privacy)
# Porcupine

[![Build Status](https://travis-ci.org/Picovoice/Porcupine.svg?branch=master)](https://travis-ci.org/Picovoice/Porcupine)
[![GitHub release](https://img.shields.io/github/release/Picovoice/Porcupine.svg)](https://github.com/Picovoice/Porcupine/releases)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/Picovoice/Porcupine/blob/master/LICENSE)

Made in Vancouver, Canada by [Picovoice](https://picovoice.ai)

Porcupine is a self-service, highly-accurate, and lightweight **wake word** (**voice control**) engine. It enables developers to
build always-listening voice-enabled applications/platforms. Porcupine is
Porcupine is a self-service, highly-accurate, and lightweight **wake word** (**voice control**) engine. It enables
developers to build always-listening voice-enabled applications/platforms. Porcupine is

* self-service. Developers are empowered to **choose any wake word** and build its model **within seconds**.
* using **deep neural networks** trained in **real-world situations**.
* compact and computationally-efficient making it suitable for **IoT** applications. It can run with as low as 200 KB of memory.
* **cross-platform**. It is implemented in fixed-point ANSI C. Currently **Raspberry Pi**, **Android**, **iOS**, **watchOS**, **Linux**,
**Mac**, **Windows**, and Web browsers are supported. Furthermore, Support for various ARM Cortex-A/M processors and a growing number of DSPs is available.
* compact and computationally-efficient making it suitable for **IoT** applications. It can run with as low as 200 KB of
memory.
* **cross-platform**. It is implemented in fixed-point ANSI C. Currently **Raspberry Pi**, **Android**, **iOS**,
**watchOS**, **Linux**, **Mac**, **Windows**, and **web browsers** are supported. Furthermore, Support for various
**ARM Cortex-A** and **ARM Cortex-M** processors and a growing number of **DSPs** is available.
* **scalable**. It can detect tens of commands concurrently with no added CPU/memory footprint.

## Table of Contents
Expand Down Expand Up @@ -43,8 +44,9 @@ build always-listening voice-enabled applications/platforms. Porcupine is

Try out Porcupine using its [interactive web demo](https://picovoice.ai/#voice-control-demo). You need a working microphone.

Try out Porcupine by downloading it's [Android demo application](https://play.google.com/store/apps/details?id=ai.picovoice.porcupine.demo&hl=en).
The demo application allows you to test Porcupine on a variety of wake words in any environment.
Try out Porcupine by downloading it's
[Android demo application](https://play.google.com/store/apps/details?id=ai.picovoice.porcupine.demo&hl=en). The demo
application allows you to test Porcupine on a variety of wake words in any environment.

![Android Demo](resources/images/demo.gif)

Expand All @@ -60,9 +62,10 @@ The demo application allows you to test Porcupine on a variety of wake words in

## Performance

A comparison between accuracy and runtime metrics of Porcupine and two other widely-used libraries, PocketSphinx and Snowboy, is provided
[here](https://github.com/Picovoice/wakeword-benchmark). Compared to the best-performing engine, Porcupine's standard model is
2.53 times more accurate, 2.6 times faster (on Raspberry Pi 3), and consumes 45% less memory.
A comparison between accuracy and runtime metrics of Porcupine and two other widely-used libraries, PocketSphinx and
Snowboy, is provided [here](https://github.com/Picovoice/wakeword-benchmark). Compared to the best-performing engine,
Porcupine's standard model is 2.53 times more accurate, 2.6 times faster (on Raspberry Pi 3), and consumes 45% less
memory.

## Model Variants

Expand All @@ -75,16 +78,18 @@ resources. Below is the comparison of runtime measurements for different variant
Standard | 7.39% | 1380 KB |
Tiny | 3.42% | 240 KB |

For accuracy comparison of different variants refer to [benchmark repository](https://github.com/Picovoice/wakeword-benchmark).
For accuracy comparison of different variants refer to
[benchmark repository](https://github.com/Picovoice/wakeword-benchmark).

## Structure of Repository

Porcupine is shipped as an ANSI C precompiled library. The binary files for supported platforms are located under
[lib/](/lib) and header files are at [include/](/include). Currently, Raspberry Pi, Android, iOS, watchOS, Linux, Mac, and Windows are supported.
If you wish to run Porcupine on any other platform, please contact us at contact@picovoice.ai.
[lib/](/lib) and header files are at [include/](/include). Currently, Raspberry Pi, Android, iOS, watchOS, Linux, Mac,
Windows, and modern web browsers are supported.

Bindings are available at [binding/](/binding) to facilitate usage from higher-level languages/platforms. Demo
applications are at [demo/](/demo). When possible, use one of the demo applications as a starting point for your own implementation.
applications are at [demo/](/demo). When possible, use one of the demo applications as a starting point for your own
implementation.

[tools/](/tools) contains utility programs. Finally, [resources/](/resources) is a placeholder for data used by
various applications within the repository.
Expand All @@ -97,9 +102,9 @@ documentation, it is assumed that the current working directory is the root of t
### Python Demo Application

This [demo application](/demo/python) allows testing Porcupine using computer's microphone. It opens an input audio
stream, monitors it using Porcupine's library, and logs the detection events into the console. Below is an
example of running the demo for hotword **Alexa** from the command line. Replace `${SYSTEM}` with the name of
the operating system on your machine (e.g. linux, mac, windows, or raspberry-pi).
stream, monitors it using Porcupine's library, and logs the detection events into the console. Below is an example of
running the demo for hotword **Alexa** from the command line. Replace `${SYSTEM}` with the name of the operating system
on your machine (e.g. linux, mac, windows, or raspberry-pi).

```bash
python demo/python/porcupine_demo.py --keyword_file_paths resources/keyword_files/alexa_${SYSTEM}.ppn
Expand Down Expand Up @@ -465,6 +470,12 @@ If you like to contribute to Porcupine, please read through [CONTRIBUTING.md](CO

## Releases

### v1.5.0 - November 13, 2018

* Improved optimizer's accuracy.
* Runtime optimization.
* Added support for running within web browsers (WebAssembly).

### v1.4.0 - July 20, 2018

* Improved accuracy across all models (specifically tiny variant).
Expand Down Expand Up @@ -503,5 +514,5 @@ commercial products without acquiring a commercial licensing agreement from Pico

Custom wake-words for other platforms are only provided with the purchase of the commercial license.

In order to inquire
about the commercial license send an email to contact@picovoice.ai with a brief description of your use case.
In order to inquire about the commercial license send an email to contact@picovoice.ai with a brief description of your
use case.
27 changes: 14 additions & 13 deletions binding/js/porcupine.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@ let Porcupine = (function () {
let frameLength;
let version;

Module.onRuntimeInitialized = async _ => {
let porcupineModule = PorcupineModule();
porcupineModule.then(function(Module) {
initWasm = Module.cwrap('pv_porcupine_wasm_init', 'number', ['number', 'number', 'number', 'number']);
releaseWasm = Module.cwrap('pv_porcupine_wasm_delete', ['number']);
processWasm = Module.cwrap('pv_porcupine_wasm_process', 'number', ['number', 'number']);
sampleRate = Module.cwrap('pv_wasm_sample_rate', 'number', [])();
frameLength = Module.cwrap('pv_porcupine_wasm_frame_length', 'number', [])();
version = Module.cwrap('pv_porcupine_wasm_version', 'string', [])();
};
});

let create = function (keywordIDs, sensitivities) {
/**
Expand All @@ -30,26 +31,26 @@ let Porcupine = (function () {
* @returns An instance of wake word detection engine.
*/
let keywordIDSizes = Int32Array.from(keywordIDs.map(keywordID => keywordID.byteLength));
let keywordIDSizesPointer = Module._malloc(keywordIDSizes.byteLength);
let keywordIDSizesBuffer = new Uint8Array(Module.HEAPU8.buffer, keywordIDSizesPointer, keywordIDSizes.byteLength);
let keywordIDSizesPointer = porcupineModule._malloc(keywordIDSizes.byteLength);
let keywordIDSizesBuffer = new Uint8Array(porcupineModule.HEAPU8.buffer, keywordIDSizesPointer, keywordIDSizes.byteLength);
keywordIDSizesBuffer.set(new Uint8Array(keywordIDSizes.buffer));

let keywordIDPointers = Uint32Array.from(keywordIDs.map(keywordID => {
let heapPointer = Module._malloc(keywordID.byteLength);
let heapBuffer = new Uint8Array(Module.HEAPU8.buffer, heapPointer, keywordID.byteLength);
let heapPointer = porcupineModule._malloc(keywordID.byteLength);
let heapBuffer = new Uint8Array(porcupineModule.HEAPU8.buffer, heapPointer, keywordID.byteLength);
heapBuffer.set(keywordID);
return heapPointer;
}));

let keywordIDPointersPointer = Module._malloc(keywordIDPointers.byteLength);
let keywordIDPointersPointer = porcupineModule._malloc(keywordIDPointers.byteLength);
let keywordIDPointersBuffer = new Uint8Array(
Module.HEAPU8.buffer,
porcupineModule.HEAPU8.buffer,
keywordIDPointersPointer,
keywordIDPointers.byteLength);
keywordIDPointersBuffer.set(new Uint8Array(keywordIDPointers.buffer));

let sensitivitiesPointer = Module._malloc(sensitivities.byteLength);
let sensitivitiesBuffer = new Uint8Array(Module.HEAPU8.buffer, sensitivitiesPointer, sensitivities.byteLength);
let sensitivitiesPointer = porcupineModule._malloc(sensitivities.byteLength);
let sensitivitiesBuffer = new Uint8Array(porcupineModule.HEAPU8.buffer, sensitivitiesPointer, sensitivities.byteLength);
sensitivitiesBuffer.set(new Uint8Array(sensitivities.buffer));

let handleWasm = initWasm(
Expand All @@ -61,15 +62,15 @@ let Porcupine = (function () {
throw new Error("failed to initialize porcupine.");
}

let pcmWasmPointer = Module._malloc(this.frameLength * 2);
let pcmWasmPointer = porcupineModule._malloc(this.frameLength * 2);

let release = function () {
/**
* Releases resources acquired by WebAssembly module.
*/

releaseWasm(handleWasm);
Module._free(pcmWasmPointer);
porcupineModule._free(pcmWasmPointer);
};

let process = function (pcmInt16Array) {
Expand All @@ -80,7 +81,7 @@ let Porcupine = (function () {
* @returns {Number} Index of detected keyword (phrase). When no keyword is detected it returns -1.
*/

let pcmWasmBuffer = new Uint8Array(Module.HEAPU8.buffer, pcmWasmPointer, pcmInt16Array.byteLength);
let pcmWasmBuffer = new Uint8Array(porcupineModule.HEAPU8.buffer, pcmWasmPointer, pcmInt16Array.byteLength);
pcmWasmBuffer.set(new Uint8Array(pcmInt16Array.buffer));

let keyword_index = processWasm(handleWasm, pcmWasmPointer);
Expand Down
2 changes: 1 addition & 1 deletion demo/android/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion demo/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'com.android.tools.build:gradle:3.1.4'
}
}

Expand Down
12 changes: 7 additions & 5 deletions demo/ios/PorcupineDemoNoWatch.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -48,26 +48,26 @@

/* Begin PBXFileReference section */
BB247359205F636700D96613 /* porcupine_params.pv */ = {isa = PBXFileReference; lastKnownFileType = file; name = porcupine_params.pv; path = ../../../lib/common/porcupine_params.pv; sourceTree = "<group>"; };
BB2473622061678900D96613 /* americano_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = file; path = americano_ios.ppn; sourceTree = "<group>"; };
BB2473622061678900D96613 /* americano_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = text; path = americano_ios.ppn; sourceTree = "<group>"; };
BB2473642061679900D96613 /* avocado_ios.ppn */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = avocado_ios.ppn; sourceTree = "<group>"; };
BB247366206167AC00D96613 /* blueberry_ios.ppn */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = blueberry_ios.ppn; sourceTree = "<group>"; };
BB247368206167BA00D96613 /* bumblebee_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = file; path = bumblebee_ios.ppn; sourceTree = "<group>"; };
BB247368206167BA00D96613 /* bumblebee_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = text; path = bumblebee_ios.ppn; sourceTree = "<group>"; };
BB24736A206167C500D96613 /* caterpillar_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = file; path = caterpillar_ios.ppn; sourceTree = "<group>"; };
BB24736C2061687C00D96613 /* christina_ios.ppn */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = christina_ios.ppn; sourceTree = "<group>"; };
BB24736E2061688D00D96613 /* dragonfly_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = file; path = dragonfly_ios.ppn; sourceTree = "<group>"; };
BB2473702061689C00D96613 /* flamingo_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = file; path = flamingo_ios.ppn; sourceTree = "<group>"; };
BB247372206168AB00D96613 /* francesca_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = text; path = francesca_ios.ppn; sourceTree = "<group>"; };
BB247374206168B800D96613 /* grapefruit_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = file; path = grapefruit_ios.ppn; sourceTree = "<group>"; };
BB247376206168C900D96613 /* grasshopper_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = text; path = grasshopper_ios.ppn; sourceTree = "<group>"; };
BB247378206168DA00D96613 /* iguana_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = file; path = iguana_ios.ppn; sourceTree = "<group>"; };
BB247378206168DA00D96613 /* iguana_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = text; path = iguana_ios.ppn; sourceTree = "<group>"; };
BB24737A206168E900D96613 /* picovoice_ios.ppn */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = picovoice_ios.ppn; sourceTree = "<group>"; };
BB24737C2061692800D96613 /* porcupine_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = file; path = porcupine_ios.ppn; sourceTree = "<group>"; };
BB24737E2061693600D96613 /* pineapple_ios.ppn */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pineapple_ios.ppn; sourceTree = "<group>"; };
BB2473802061694500D96613 /* raspberry_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = file; path = raspberry_ios.ppn; sourceTree = "<group>"; };
BB2473802061694500D96613 /* raspberry_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = text; path = raspberry_ios.ppn; sourceTree = "<group>"; };
BB2473822061694F00D96613 /* vancouver_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = file; path = vancouver_ios.ppn; sourceTree = "<group>"; };
BB2473842061695A00D96613 /* terminator_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = text; path = terminator_ios.ppn; sourceTree = "<group>"; };
BB24738C206312DC00D96613 /* PorcupineManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PorcupineManager.swift; path = ../../../binding/ios/PorcupineManager.swift; sourceTree = "<group>"; };
BB24738E20633DED00D96613 /* alexa_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = file; path = alexa_ios.ppn; sourceTree = "<group>"; };
BB24738E20633DED00D96613 /* alexa_ios.ppn */ = {isa = PBXFileReference; lastKnownFileType = text; path = alexa_ios.ppn; sourceTree = "<group>"; };
BB65C7AF205EEBB300E8770E /* module.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
BB65C7B1205F4BF400E8770E /* libpv_porcupine.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpv_porcupine.a; path = ../../lib/ios/libpv_porcupine.a; sourceTree = "<group>"; };
BBE66BCA205DD6F7006005B1 /* PorcupineDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PorcupineDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -460,6 +460,7 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5KNTYR3JP3;
INFOPLIST_FILE = "$(SRCROOT)/PorcupineDemo/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 12.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = "${SRCROOT}/../../lib/ios";
PRODUCT_BUNDLE_IDENTIFIER = picovoice.porcupine;
Expand All @@ -476,6 +477,7 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 5KNTYR3JP3;
INFOPLIST_FILE = "$(SRCROOT)/PorcupineDemo/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 12.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = "${SRCROOT}/../../lib/ios";
PRODUCT_BUNDLE_IDENTIFIER = picovoice.porcupine;
Expand Down
22 changes: 21 additions & 1 deletion demo/js/pv_porcupine.js

Large diffs are not rendered by default.

Binary file modified demo/js/pv_porcupine.wasm
Binary file not shown.
Loading

0 comments on commit 8124a42

Please sign in to comment.