diff --git a/.gitignore b/.gitignore index 99f872b9..95d2ab6c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,9 @@ snowboydetect.py /examples/C++/pa_stable_v19_20140130.tgz /examples/C++/portaudio /examples/C++/demo + +/swig/Android/OpenBLAS-0.2.18.tar.gz +/swig/Android/OpenBLAS-Android/ +/swig/Android/java/ +/swig/Android/jniLibs/ + diff --git a/README.md b/README.md index d278c136..b372cc19 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ by [KITT.AI](http://kitt.ai). [Full Documentation](https://snowboy.kitt.ai/docs) -Version: 1.0.2 (5/24/2016) +Version: 1.0.3 (6/4/2016) Snowboy is a customizable hotword detection engine for you to create your own hotword like "OK Google" or "Alexa". It is powered by deep neural networks and has the following properties: @@ -26,12 +26,14 @@ Currently Snowboy supports: * all versions of Raspberry Pi (with Raspbian based on Debian Jessie 8.0) * 64bit Mac OS X * 64bit Ubuntu (12.04 and 14.04) +* iOS +* Android -It ships in the form of a **C library** with **Python** wrappers generated by SWIG. We welcome wrappers for other languages -- feel free to send a pull request! +It ships in the form of a **C library** with language-dependent wrappers generated by SWIG. We welcome wrappers for new languages -- feel free to send a pull request! If you want support on other hardware/OS, please send your request to [snowboy@kitt.ai](mailto:snowboy.kitt.ai) -## Precompiled Binaries +## Precompiled Binaries with Python Demo * 64 bit Ubuntu [12.04](https://s3-us-west-2.amazonaws.com/snowboy/snowboy-releases/ubuntu1204-x86_64-1.0.2.tar.bz2) / [14.04](https://s3-us-west-2.amazonaws.com/snowboy/snowboy-releases/ubuntu1404-x86_64-1.0.2.tar.bz2) * [MacOS X](https://s3-us-west-2.amazonaws.com/snowboy/snowboy-releases/osx-x86_64-1.0.2.tar.bz2) @@ -84,7 +86,47 @@ SWIG will generate a `_snowboydetect.so` file and a simple (but hard-to-read) py Feel free to adapt the `Makefile` in `swig/Python` to your own system's setting if you cannot `make` it. -## Quick Start +## Compile an iOS Wrapper + +Using Snowboy library in Objective-C does not really require a wrapper. It is basically the same as using C++ library in Objective-C. We have compiled a "fat" static library for iOS devices, see the library here `lib/ios/libsnowboy-detect.a`. + +To initialize Snowboy detector in Objective-C: + + snowboy::SnowboyDetect* snowboyDetector = new snowboy::SnowboyDetect( + std::string([[[NSBundle mainBundle]pathForResource:@"common" ofType:@"res"] UTF8String]), + std::string([[[NSBundle mainBundle]pathForResource:@"snowboy" ofType:@"umdl"] UTF8String])); + snowboyDetector->SetSensitivity("0.45"); // Sensitivity for each hotword + snowboyDetector->SetAudioGain(2.0); // Audio gain for detection + +To run hotword detection in Objective-C: + + int result = snowboyDetector->RunDetection(buffer[0], bufferSize); // buffer[0] is a float array + +You may want to play with the frequency of the calls to `RunDetection()`, which controls the CPU usage and the detection latency. + +## Compile an Android Wrapper + + cd swig/Android + # Make sure you set up the NDKROOT variable in Makefile before you run. + make + +Using Snowboy library on Android devices is a little bit tricky. We have compiled Snowboy using Android's cross-compilation toolchain for ARMV7 architecture, see the library here `lib/android/armv7a/libsnowboy-detect.a`. We then use SWIG to generate the Java wrapper, and use Android's cross-compilation toolchain to generate the corresponding JNI libraries. After running `make`, two directories will be created: `java` and `jniLibs`. Copy these two directories to your Android app directory (e.g., `app/src/main/`) and you should be able to call Snowboy funcitons within Java. + +To initialize Snowboy detector in Java: + + # Assume you put the model related files under /sdcard/snowboy/ + SnowboyDetect snowboyDetector = new SnowboyDetect("/sdcard/snowboy/common.res", + "/sdcard/snowboy/snowboy.umdl"); + snowboyDetector.SetSensitivity("0.45"); // Sensitivity for each hotword + snowboyDetector.SetAudioGain(2.0); // Audio gain for detection + +To run hotword detection in Java: + + int result = snowboyDetector.RunDetection(buffer, buffer.length); // buffer is a short array. + +You may want to play with the frequency of the calls to `RunDetection()`, which controls the CPU usage and the detection latency. + +## Quick Start for Python Demo Go to the `examples/Python` folder and open your python console: @@ -120,6 +162,13 @@ See [Full Documentation](https://snowboy.kitt.ai/docs). ## Change Log +**v1.0.3, 6/4/2016** + +* Updated universal `snowboy.umdl` model to make it more robust in non-speech environment. +* Fixed bug when using float as input data. +* Added library support for Android ARMV7 architecture. +* Added library for iOS. + **v1.0.2, 5/24/2016** * Updated universal `snowboy.umdl` model diff --git a/examples/C++/demo.mk b/examples/C++/demo.mk index 22b83700..d8ce19e0 100644 --- a/examples/C++/demo.mk +++ b/examples/C++/demo.mk @@ -30,7 +30,8 @@ else ifeq ($(shell uname), Linux) CXXFLAGS += -I$(TOPDIR) -std=c++0x -Wall -Wno-sign-compare \ -Wno-unused-local-typedefs -Winit-self -rdynamic \ -DHAVE_POSIX_MEMALIGN -I$(PORTAUDIOINC) - LDLIBS += -ldl -lm -Wl,-Bstatic -Wl,-Bdynamic -lrt -lpthread $(PORTAUDIOLIBS) + LDLIBS += -ldl -lm -Wl,-Bstatic -Wl,-Bdynamic -lrt -lpthread $(PORTAUDIOLIBS)\ + -L/usr/lib/atlas-base -lf77blas -lcblas -llapack_atlas -latlas ifneq ($(wildcard $(PORTAUDIOINC)/pa_linux_alsa.h),) LDLIBS += -lasound endif diff --git a/lib/android/armv7a/libsnowboy-detect.a b/lib/android/armv7a/libsnowboy-detect.a new file mode 100644 index 00000000..ded8a0aa Binary files /dev/null and b/lib/android/armv7a/libsnowboy-detect.a differ diff --git a/lib/ios/libsnowboy-detect.a b/lib/ios/libsnowboy-detect.a index d67849e5..0a4ff5f8 100644 Binary files a/lib/ios/libsnowboy-detect.a and b/lib/ios/libsnowboy-detect.a differ diff --git a/lib/osx/libsnowboy-detect.a b/lib/osx/libsnowboy-detect.a index 0e63c25d..bf6772cc 100644 Binary files a/lib/osx/libsnowboy-detect.a and b/lib/osx/libsnowboy-detect.a differ diff --git a/lib/rpi/libsnowboy-detect.a b/lib/rpi/libsnowboy-detect.a index d2f007d0..346196be 100644 Binary files a/lib/rpi/libsnowboy-detect.a and b/lib/rpi/libsnowboy-detect.a differ diff --git a/lib/ubuntu64/libsnowboy-detect.a b/lib/ubuntu64/libsnowboy-detect.a index 6f1a6040..19f474a3 100644 Binary files a/lib/ubuntu64/libsnowboy-detect.a and b/lib/ubuntu64/libsnowboy-detect.a differ diff --git a/resources/snowboy.umdl b/resources/snowboy.umdl index f19af489..142d6506 100644 Binary files a/resources/snowboy.umdl and b/resources/snowboy.umdl differ diff --git a/swig/Android/Makefile b/swig/Android/Makefile new file mode 100644 index 00000000..59424207 --- /dev/null +++ b/swig/Android/Makefile @@ -0,0 +1,74 @@ +# Example Makefile that wrappers snowboy c++ library (snowboy-detect.a) through +# JNI interface, using swig. + +# When you extract Android toolchain from Android NDK, make sure you supply +# --stl=libc++ option. This Makefile is optimized for armv7-a architecture. + +# Some versions of swig does not work well. We prefer compiling swig from source +# code. We have tested swig-3.0.7.tar.gz. +SWIG := swig + +# Please specify your NDK root directory here. +NDKROOT := +APILEVEL := 17 + +SNOWBOYDETECTSWIGITF = snowboy-detect-swig.i +SNOWBOYDETECTSWIGOBJ = snowboy-detect-swig.o +SNOWBOYDETECTSWIGCC = snowboy-detect-swig.cc +SNOWBOYDETECTJAVAPKG = ai.kitt.snowboy +SNOWBOYDETECTJAVAPKGDIR = java/ai/kitt/snowboy/ +SNOWBOYDETECTSWIGLIBFILE = libsnowboy-detect-android.so +OPENBLASLIBFILE = OpenBLAS-Android/install/lib/libopenblas.a + +ARCH := arm +TOPDIR := ../../ +LDFLAGS := + +CXXFLAGS := -O3 --sysroot=$(NDKROOT)/platforms/android-$(APILEVEL)/arch-$(ARCH) +LDLIBS := -L$(NDKROOT)/platforms/android-$(APILEVEL)/arch-$(ARCH)/usr/lib + +ifeq ($(ARCH), arm) + CXX := arm-linux-androideabi-g++ + STRIP := arm-linux-androideabi-strip + OPENBLASTARGET := ARMV7 + SNOWBOYDETECTLIBFILE = $(TOPDIR)/lib/android/armv7a/libsnowboy-detect.a + CXXFLAGS += -shared -std=c++0x -rdynamic -I$(TOPDIR) -Wl,--fix-cortex-a8 \ + -Wl,--no-warn-mismatch -Wl,--no-undefined -Wl,-z,noexecstack \ + -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings \ + -Wno-sign-compare -Wa,--noexecstack -Wformat -Werror=format-security \ + -fno-rtti -ffunction-sections -funwind-tables -fstack-protector-strong \ + -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 \ + -fno-strict-aliasing -mthumb -no-canonical-prefixes -march=armv7-a \ + -mfpu=vfpv3-d16 -mhard-float -D_NDK_MATH_NO_SOFTFP=1 -DANDROID + LDLIBS += \ + -L$(NDKROOT)/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a-hard/thumb/ \ + -lc++_static -lgcc -lm_hard -ldl -lc -lm + SNOWBOYDETECTSWIGLIBFILE := jniLibs/armeabi-v7a/$(SNOWBOYDETECTSWIGLIBFILE) + SNOWBOYDETECTSWIGLIBNAME := $(shell basename $(SNOWBOYDETECTSWIGLIBFILE)) +endif + +all: $(SNOWBOYSWIGLIBFILE) $(SNOWBOYDETECTSWIGLIBFILE) + +%.a: + $(MAKE) -C ${@D} ${@F} + +$(OPENBLASLIBFILE): + @-./install_openblas_android.sh $(ARCH) $(OPENBLASTARGET) + +$(SNOWBOYDETECTSWIGCC): $(SNOWBOYDETECTSWIGITF) + @-mkdir -p $(SNOWBOYDETECTJAVAPKGDIR) + $(SWIG) -I$(TOPDIR) -c++ -java -package $(SNOWBOYDETECTJAVAPKG) -outdir \ + $(SNOWBOYDETECTJAVAPKGDIR) -o $(SNOWBOYDETECTSWIGCC) $(SNOWBOYDETECTSWIGITF) + +$(SNOWBOYDETECTSWIGOBJ): $(SNOWBOYDETECTSWIGCC) + $(CXX) $(CXXFLAGS) -c $(SNOWBOYDETECTSWIGCC) -o $(SNOWBOYDETECTSWIGOBJ) + +$(SNOWBOYDETECTSWIGLIBFILE): $(OPENBLASLIBFILE) $(SNOWBOYDETECTSWIGOBJ) $(SNOWBOYDETECTLIBFILE) + @-mkdir -p `dirname $(SNOWBOYDETECTSWIGLIBFILE)` + $(CXX) -Wl,-soname,$(SNOWBOYDETECTSWIGLIBNAME) $(CXXFLAGS) $(LDFLAGS) \ + $(SNOWBOYDETECTSWIGOBJ) $(SNOWBOYDETECTLIBFILE) $(OPENBLASLIBFILE) \ + $(LDLIBS) -o $(SNOWBOYDETECTSWIGLIBFILE) + $(STRIP) --strip-unneeded $(SNOWBOYDETECTSWIGLIBFILE) + +clean: + -rm -rf *.o *.a *.so java jniLibs $(SNOWBOYDETECTSWIGCC) diff --git a/swig/Android/install_openblas_android.sh b/swig/Android/install_openblas_android.sh new file mode 100755 index 00000000..4dc20d4c --- /dev/null +++ b/swig/Android/install_openblas_android.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# This script compiles OpenBLAS for Android with the given architecture. The +# prebuild Android NDK toolchains do not include Fortran, hence parts like +# LAPACK will not be built. + +ARCH=$1 +TARGET=$2 + +if [ ! -f OpenBLAS-0.2.18.tar.gz ]; then + wget -T 10 -t 3 https://codeload.github.com/xianyi/OpenBLAS/tar.gz/v0.2.18 \ + -O OpenBLAS-0.2.18.tar.gz || exit 1; +fi + +tar -xvzf OpenBLAS-0.2.18.tar.gz || exit 1; +mv OpenBLAS-0.2.18 OpenBLAS-Android + +cd OpenBLAS-Android +make TARGET=${TARGET} HOSTCC=gcc \ + CC=${ARCH}-linux-androideabi-gcc NOFORTRAN=1 || exit 1; +make PREFIX=`pwd`/install install || exit 1; diff --git a/swig/Android/snowboy-detect-swig.i b/swig/Android/snowboy-detect-swig.i new file mode 100644 index 00000000..d229097e --- /dev/null +++ b/swig/Android/snowboy-detect-swig.i @@ -0,0 +1,20 @@ +// snowboy-detect-swig.i + +// Copyright 2016 KITT.AI (author: Guoguo Chen) + +%module snowboy + +// Suppress SWIG warnings. +#pragma SWIG nowarn=SWIGWARN_PARSE_NESTED_CLASS +%include "arrays_java.i" +%include "std_string.i" + +%apply float[] {float*}; +%apply short[] {int16_t*}; +%apply int[] {int32_t*}; + +%{ +#include "include/snowboy-detect.h" +%} + +%include "include/snowboy-detect.h"