Adding MegaDrone sample (from AES talk)
diff --git a/samples/MegaDrone/.gitignore b/samples/MegaDrone/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/samples/MegaDrone/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/samples/MegaDrone/CMakeLists.txt b/samples/MegaDrone/CMakeLists.txt
new file mode 100644
index 0000000..ed9a7df
--- /dev/null
+++ b/samples/MegaDrone/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.4.1)
+
+
+### INCLUDE OBOE LIBRARY ###
+
+# Set the path to the Oboe library directory
+set (OBOE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..)
+
+# Add the Oboe library as a subproject. Since Oboe is an out-of-tree source library we must also
+# specify a binary directory
+add_subdirectory(${OBOE_DIR} ./oboe-bin)
+
+# Include the Oboe headers
+include_directories(${OBOE_DIR}/include)
+
+### END OBOE INCLUDE SECTION ###
+
+
+add_library( megadrone SHARED
+        src/main/cpp/native-lib.cpp
+        src/main/cpp/Synth.cpp)
+
+target_link_libraries( megadrone log oboe )
+
+# Make the Oboe public headers available to our app
+include_directories (${OBOE_DIR}/include)
+
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Ofast")
diff --git a/samples/MegaDrone/README.md b/samples/MegaDrone/README.md
new file mode 100644
index 0000000..4aed5de
--- /dev/null
+++ b/samples/MegaDrone/README.md
@@ -0,0 +1,43 @@
+Mega Drone
+==========
+Ever wondered what 100 square waves sound like when played together? Well now you can find out! 
+
+Mega Drone is an app which creates 100 oscillators, combines their output in a mixer and plays the resulting sound. 
+
+This sample demonstrates how to obtain the lowest latency by: 
+
+1) Leaving Oboe to choose the best default stream properties for the current device
+2) Setting performance mode to LowLatency
+3) Setting sharing mode to Exclusive
+4) Setting the buffer size to 2 bursts
+
+This code was presented at [AES Milan](http://www.aes.org/events/144/) as part of a live coding demonstration. 
+
+The following article explaining how to debug CPU performance problems may also be useful when looking at this code 
+
+Implementation details
+---
+The stream properties are left to Oboe as such the app must output audio data in a format which matches that of the stream. 
+
+Four different formats are supported: 
+
+|Channel count|Format|
+|-------------|------|
+|1 - Mono|16-bit int|
+|2 - Stereo|16-bit int|
+|1 - Mono|Float|
+|1 - Stereo|Float|
+
+The signal chain for mono streams is: 
+
+    Oscillators->Mixer
+
+For stereo chains a mono to stereo converter is added to the end of the chain: 
+
+    Oscillators->Mixer->MonoToStereo
+ 
+The compiler optimization flag `-Ofast` can be found in [CMakeLists.txt](CMakeLists.txt). 
+ 
+Screenshots
+-----------
+![mega-drone-screenshot](mega-drone-screenshot.png)
\ No newline at end of file
diff --git a/samples/MegaDrone/build.gradle b/samples/MegaDrone/build.gradle
new file mode 100644
index 0000000..cbe4ffc
--- /dev/null
+++ b/samples/MegaDrone/build.gradle
@@ -0,0 +1,49 @@
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion 27
+    defaultConfig {
+        applicationId "com.example.oboe.megadrone"
+        minSdkVersion 16
+        targetSdkVersion 27
+        versionCode 1
+        versionName "1.0"
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+        externalNativeBuild {
+            cmake {
+                cppFlags "-std=c++14"
+            }
+        }
+    }
+    signingConfigs {
+        release {
+            storeFile new File("${System.properties['user.home']}/.android/debug.keystore")
+            storePassword 'android'
+            storeType "jks"
+            keyAlias 'androiddebugkey'
+            keyPassword 'android'
+        }
+    }
+    buildTypes {
+        release {
+            signingConfig signingConfigs.release
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+            debuggable false
+        }
+    }
+    externalNativeBuild {
+        cmake {
+            path "CMakeLists.txt"
+        }
+    }
+}
+
+dependencies {
+    implementation fileTree(dir: 'libs', include: ['*.jar'])
+    implementation 'com.android.support:appcompat-v7:27.1.1'
+    implementation 'com.android.support.constraint:constraint-layout:1.1.0'
+    testImplementation 'junit:junit:4.12'
+    androidTestImplementation 'com.android.support.test:runner:1.0.2'
+    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
+}
diff --git a/samples/MegaDrone/megadrone-screenshot.png b/samples/MegaDrone/megadrone-screenshot.png
new file mode 100644
index 0000000..acdb98e
--- /dev/null
+++ b/samples/MegaDrone/megadrone-screenshot.png
Binary files differ
diff --git a/samples/MegaDrone/proguard-rules.pro b/samples/MegaDrone/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/samples/MegaDrone/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/samples/MegaDrone/src/main/AndroidManifest.xml b/samples/MegaDrone/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ba26543
--- /dev/null
+++ b/samples/MegaDrone/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.example.oboe.megadrone">
+
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <activity android:name="com.example.oboe.megadrone.MainActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
\ No newline at end of file
diff --git a/samples/MegaDrone/src/main/cpp/Constants.h b/samples/MegaDrone/src/main/cpp/Constants.h
new file mode 100644
index 0000000..6011f35
--- /dev/null
+++ b/samples/MegaDrone/src/main/cpp/Constants.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEGADRONE_CONSTANTS_H
+#define MEGADRONE_CONSTANTS_H
+
+constexpr int kMonoChannelCount = 1;
+constexpr int kStereoChannelCount = 2;
+
+#endif //MEGADRONE_CONSTANTS_H
diff --git a/samples/MegaDrone/src/main/cpp/Mixer.h b/samples/MegaDrone/src/main/cpp/Mixer.h
new file mode 100644
index 0000000..2d45dbc
--- /dev/null
+++ b/samples/MegaDrone/src/main/cpp/Mixer.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RHYTHMGAME_MIXER_H
+#define RHYTHMGAME_MIXER_H
+
+#include "RenderableAudio.h"
+
+constexpr int32_t kBufferSize = 192*10; // Temporary buffer is used for mixing
+constexpr uint8_t kMaxTracks = 100;
+
+template <typename T>
+class Mixer : public RenderableAudio<T> {
+
+public:
+
+    void renderAudio(T *audioData, int32_t numFrames) {
+
+        // Zero out the incoming container array
+        for (int j = 0; j < numFrames; ++j) {
+            audioData[j] = 0;
+        }
+
+        for (int i = 0; i < mNextFreeTrackIndex; ++i) {
+            mTracks[i]->renderAudio(mixingBuffer, numFrames);
+
+            for (int j = 0; j < numFrames; ++j) {
+                audioData[j] += mixingBuffer[j];
+            }
+        }
+    }
+
+    void addTrack(RenderableAudio<T> *renderer){
+        mTracks[mNextFreeTrackIndex++] = renderer;
+    }
+
+private:
+    T mixingBuffer[kBufferSize]; // TODO: smart pointer
+    RenderableAudio<T>* mTracks[kMaxTracks]; // TODO: this might be better as a linked list for easy track removal
+    uint8_t mNextFreeTrackIndex = 0;
+};
+
+
+#endif //RHYTHMGAME_MIXER_H
diff --git a/samples/MegaDrone/src/main/cpp/MonoToStereo.h b/samples/MegaDrone/src/main/cpp/MonoToStereo.h
new file mode 100644
index 0000000..85cce4d
--- /dev/null
+++ b/samples/MegaDrone/src/main/cpp/MonoToStereo.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEGADRONE_MONOTOSTEREO_H
+#define MEGADRONE_MONOTOSTEREO_H
+
+#include "RenderableAudio.h"
+#include "Constants.h"
+
+template <typename T>
+class MonoToStereo : public RenderableAudio<T> {
+
+public:
+
+    MonoToStereo(RenderableAudio<T> *input) : mInput(input){};
+
+    void renderAudio(T *audioData, int32_t numFrames) override {
+
+        // We assume that audioData has sufficient frames to hold the stereo output, so copy each
+        // frame in the input to the output twice
+        // e.g. 123 => 112233
+        for (int i = 0; i < numFrames; ++i) {
+            mInput->renderAudio(audioData+(i*kStereoChannelCount), 1);
+            audioData[(i*kStereoChannelCount)+1] = audioData[i*kStereoChannelCount];
+        }
+    }
+
+    RenderableAudio<T> *mInput;
+};
+
+
+#endif //MEGADRONE_MONOTOSTEREO_H
diff --git a/samples/MegaDrone/src/main/cpp/Oscillator.h b/samples/MegaDrone/src/main/cpp/Oscillator.h
new file mode 100644
index 0000000..a4e9cbb
--- /dev/null
+++ b/samples/MegaDrone/src/main/cpp/Oscillator.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef MEGADRONE_OSCILLATOR_H
+#define MEGADRONE_OSCILLATOR_H
+
+
+#include <cstdint>
+#include <atomic>
+#include <math.h>
+#include "RenderableAudio.h"
+
+constexpr double kDefaultFrequency = 440.0;
+constexpr int32_t kDefaultSampleRate = 48000;
+constexpr double kPi = M_PI;
+constexpr double kTwoPi = kPi * 2;
+
+template <typename T>
+class Oscillator : public RenderableAudio<T> {
+
+public:
+    ~Oscillator(){};
+
+    void setWaveOn(bool isWaveOn){
+        mIsWaveOn.store(isWaveOn);
+    };
+
+    void setSampleRate(int32_t sampleRate){
+        mSampleRate = sampleRate;
+        updatePhaseIncrement();
+    };
+
+    void setFrequency(double frequency) {
+        mFrequency = frequency;
+        updatePhaseIncrement();
+    };
+
+    void setAmplitude(T amplitude){
+        mAmplitude = amplitude;
+    };
+
+    // From RenderableAudio<T>
+    void renderAudio(T *audioData, int32_t numFrames) {
+
+        if (mIsWaveOn){
+            for (int i = 0; i < numFrames; ++i) {
+
+                // Sine wave (sinf)
+                //audioData[i*kChannelCount] = sinf(mPhase) * mAmplitude;
+
+                // Square wave
+                if (mPhase <= kPi){
+                    audioData[i] = -mAmplitude;
+                } else {
+                    audioData[i] = mAmplitude;
+                }
+
+                mPhase += mPhaseIncrement;
+                if (mPhase > kTwoPi) mPhase -= kTwoPi;
+            }
+        } else {
+            for (int i = 0; i < numFrames; ++i) {
+                audioData[i] = 0;
+            }
+        }
+    };
+
+private:
+    std::atomic<bool> mIsWaveOn{false};
+    float mPhase = 0.0;
+    std::atomic<float> mAmplitude { 0.0 };
+    std::atomic<double> mPhaseIncrement { 0.0 };
+    double mFrequency = kDefaultFrequency;
+    int32_t mSampleRate = kDefaultSampleRate;
+
+    void updatePhaseIncrement(){
+        mPhaseIncrement.store((kTwoPi * mFrequency) / (double) mSampleRate);
+    };
+};
+
+
+#endif //MEGADRONE_OSCILLATOR_H
diff --git a/samples/MegaDrone/src/main/cpp/RenderableAudio.h b/samples/MegaDrone/src/main/cpp/RenderableAudio.h
new file mode 100644
index 0000000..756ed72
--- /dev/null
+++ b/samples/MegaDrone/src/main/cpp/RenderableAudio.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEGADRONE_RENDERABLEAUDIO_H
+#define MEGADRONE_RENDERABLEAUDIO_H
+
+
+#include <cstdint>
+
+template <typename T>
+class RenderableAudio {
+
+public:
+    virtual ~RenderableAudio() = default;
+    virtual void renderAudio(T *audioData, int32_t numFrames) = 0;
+};
+
+
+#endif //MEGADRONE_RENDERABLEAUDIO_H
diff --git a/samples/MegaDrone/src/main/cpp/Synth.cpp b/samples/MegaDrone/src/main/cpp/Synth.cpp
new file mode 100644
index 0000000..d3fde2c
--- /dev/null
+++ b/samples/MegaDrone/src/main/cpp/Synth.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Synth.h"
+#include "Constants.h"
+#include "MonoToStereo.h"
+
+void Synth::start() {
+
+    AudioStreamBuilder builder;
+    builder.setCallback(this);
+    builder.setPerformanceMode(PerformanceMode::LowLatency);
+    builder.setSharingMode(SharingMode::Exclusive);
+
+    builder.openStream(&mStream);
+
+    const float baseOscFrequency = 116.0;
+    const float divisor = 33;
+    const float amplitude = 0.009;
+
+    if (mStream->getFormat() == AudioFormat::Float){
+
+        mMixerFloat = std::make_unique<Mixer<float>>();
+
+        // Spin up the oscillators (float versions)
+        for (int i = 0; i < kNumOscillators; ++i) {
+            mOscsFloat[i].setSampleRate(mStream->getSampleRate());
+            mOscsFloat[i].setFrequency(baseOscFrequency+((float)i/divisor));
+            mOscsFloat[i].setAmplitude(amplitude);
+            mMixerFloat->addTrack(&mOscsFloat[i]);
+        }
+
+        if (mStream->getChannelCount() == kStereoChannelCount){
+            mOutputStageFloat = std::make_shared<MonoToStereo<float>>(mMixerFloat.get());
+        } else if (mStream->getChannelCount() == kMonoChannelCount){
+            mOutputStageFloat = mMixerFloat;
+        }
+
+    } else {
+
+        mMixerInt16 = std::make_unique<Mixer<int16_t>>();
+
+        // Spin up the oscillators (16-bit int versions)
+        for (int i = 0; i < kNumOscillators; ++i) {
+            mOscsInt16[i].setSampleRate(mStream->getSampleRate());
+            mOscsInt16[i].setFrequency(baseOscFrequency+((float)i/divisor));
+            mOscsInt16[i].setAmplitude((int16_t)(amplitude * INT16_MAX));
+            mMixerInt16->addTrack(&mOscsInt16[i]);
+        }
+
+        if (mStream->getChannelCount() == kStereoChannelCount){
+            mOutputStageInt16 = std::make_shared<MonoToStereo<int16_t>>(mMixerInt16.get());
+        } else if (mStream->getChannelCount() == kMonoChannelCount){
+            mOutputStageInt16 = mMixerInt16;
+        }
+    }
+
+    mStream->setBufferSizeInFrames(mStream->getFramesPerBurst() * 2);
+    mStream->requestStart();
+}
+
+void Synth::tap(bool isOn) {
+
+    if (mStream){
+        if (mStream->getFormat() == AudioFormat::Float){
+            for (auto &osc : mOscsFloat) osc.setWaveOn(isOn);
+        } else {
+            for (auto &osc : mOscsInt16) osc.setWaveOn(isOn);
+        }
+    }
+}
+
+DataCallbackResult
+Synth::onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) {
+
+    if (mStream->getFormat() == AudioFormat::Float){
+        mOutputStageFloat->renderAudio(static_cast<float *>(audioData), numFrames);
+    } else {
+        mOutputStageInt16->renderAudio(static_cast<int16_t *>(audioData), numFrames);
+    }
+
+    return DataCallbackResult::Continue;
+}
diff --git a/samples/MegaDrone/src/main/cpp/Synth.h b/samples/MegaDrone/src/main/cpp/Synth.h
new file mode 100644
index 0000000..d83d50a
--- /dev/null
+++ b/samples/MegaDrone/src/main/cpp/Synth.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEGADRONE_AUDIOENGINE_H
+#define MEGADRONE_AUDIOENGINE_H
+
+#include <array>
+
+#include <oboe/Oboe.h>
+#include "Oscillator.h"
+#include "Mixer.h"
+
+constexpr int kNumOscillators = 100;
+
+using namespace oboe;
+
+class Synth : public AudioStreamCallback {
+public:
+    void start();
+    void tap(bool isOn);
+
+    DataCallbackResult
+    onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) override;
+
+private:
+    AudioStream *mStream;
+
+    // Rendering objects for 16-bit integer output
+    std::array<Oscillator<int16_t>, kNumOscillators> mOscsInt16;
+    std::shared_ptr<Mixer<int16_t>> mMixerInt16;
+    std::shared_ptr<RenderableAudio<int16_t>> mOutputStageInt16;
+
+    // Rendering objects for floating point output
+    std::array<Oscillator<float>, kNumOscillators> mOscsFloat;
+    std::shared_ptr<Mixer<float>> mMixerFloat;
+    std::shared_ptr<RenderableAudio<float>> mOutputStageFloat;
+
+
+
+};
+
+
+#endif //MEGADRONE_AUDIOENGINE_H
diff --git a/samples/MegaDrone/src/main/cpp/native-lib.cpp b/samples/MegaDrone/src/main/cpp/native-lib.cpp
new file mode 100644
index 0000000..c7e55b4
--- /dev/null
+++ b/samples/MegaDrone/src/main/cpp/native-lib.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+#include <string>
+#include "Synth.h"
+
+Synth engine;
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_example_oboe_megadrone_MainActivity_startEngine(JNIEnv *env, jobject instance) {
+
+    engine.start();
+}
+
+extern "C"
+JNIEXPORT void JNICALL
+Java_com_example_oboe_megadrone_MainActivity_tap(JNIEnv *env, jobject instance, jboolean b) {
+
+    engine.tap(b);
+}
\ No newline at end of file
diff --git a/samples/MegaDrone/src/main/java/com/example/oboe/megadrone/MainActivity.java b/samples/MegaDrone/src/main/java/com/example/oboe/megadrone/MainActivity.java
new file mode 100644
index 0000000..efe67e2
--- /dev/null
+++ b/samples/MegaDrone/src/main/java/com/example/oboe/megadrone/MainActivity.java
@@ -0,0 +1,58 @@
+package com.example.oboe.megadrone;
+
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.view.MotionEvent;
+
+public class MainActivity extends AppCompatActivity {
+
+    // Used to load the 'native-lib' library on application startup.
+    static {
+        System.loadLibrary("megadrone");
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        startEngine();
+    }
+
+    private native void startEngine();
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+
+        if (event.getAction() == MotionEvent.ACTION_DOWN){
+            tap(true);
+        } else if (event.getAction() == MotionEvent.ACTION_UP){
+            tap(false);
+        }
+
+
+        return super.onTouchEvent(event);
+    }
+
+    private native void tap(boolean b);
+
+
+}
+
+
diff --git a/samples/MegaDrone/src/main/res/drawable-v24/ic_launcher_foreground.xml b/samples/MegaDrone/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..1f6bb29
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:aapt="http://schemas.android.com/aapt"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillType="evenOdd"
+        android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000">
+        <aapt:attr name="android:fillColor">
+            <gradient
+                android:endX="78.5885"
+                android:endY="90.9159"
+                android:startX="48.7653"
+                android:startY="61.0927"
+                android:type="linear">
+                <item
+                    android:color="#44000000"
+                    android:offset="0.0" />
+                <item
+                    android:color="#00000000"
+                    android:offset="1.0" />
+            </gradient>
+        </aapt:attr>
+    </path>
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillType="nonZero"
+        android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
+        android:strokeWidth="1"
+        android:strokeColor="#00000000" />
+</vector>
diff --git a/samples/MegaDrone/src/main/res/drawable/ic_launcher_background.xml b/samples/MegaDrone/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..0d025f9
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="108dp"
+    android:height="108dp"
+    android:viewportWidth="108"
+    android:viewportHeight="108">
+    <path
+        android:fillColor="#008577"
+        android:pathData="M0,0h108v108h-108z" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M9,0L9,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,0L19,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,0L29,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,0L39,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,0L49,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,0L59,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,0L69,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,0L79,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M89,0L89,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M99,0L99,108"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,9L108,9"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,19L108,19"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,29L108,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,39L108,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,49L108,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,59L108,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,69L108,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,79L108,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,89L108,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M0,99L108,99"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,29L89,29"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,39L89,39"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,49L89,49"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,59L89,59"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,69L89,69"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M19,79L89,79"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M29,19L29,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M39,19L39,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M49,19L49,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M59,19L59,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M69,19L69,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+    <path
+        android:fillColor="#00000000"
+        android:pathData="M79,19L79,89"
+        android:strokeWidth="0.8"
+        android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/samples/MegaDrone/src/main/res/layout/activity_main.xml b/samples/MegaDrone/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..2d6f544
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/layout/activity_main.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".MainActivity">
+
+    <TextView
+        android:id="@+id/sample_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Tap anywhere to play"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout>
\ No newline at end of file
diff --git a/samples/MegaDrone/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/samples/MegaDrone/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/samples/MegaDrone/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/samples/MegaDrone/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@drawable/ic_launcher_background" />
+    <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/samples/MegaDrone/src/main/res/mipmap-hdpi/ic_launcher.png b/samples/MegaDrone/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..898f3ed
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/MegaDrone/src/main/res/mipmap-hdpi/ic_launcher_round.png b/samples/MegaDrone/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dffca36
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/MegaDrone/src/main/res/mipmap-mdpi/ic_launcher.png b/samples/MegaDrone/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..64ba76f
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/MegaDrone/src/main/res/mipmap-mdpi/ic_launcher_round.png b/samples/MegaDrone/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..dae5e08
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/MegaDrone/src/main/res/mipmap-xhdpi/ic_launcher.png b/samples/MegaDrone/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..e5ed465
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/MegaDrone/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/samples/MegaDrone/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..14ed0af
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/MegaDrone/src/main/res/mipmap-xxhdpi/ic_launcher.png b/samples/MegaDrone/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b0907ca
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/MegaDrone/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/samples/MegaDrone/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..d8ae031
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/MegaDrone/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/samples/MegaDrone/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..2c18de9
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/MegaDrone/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/samples/MegaDrone/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..beed3cd
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/MegaDrone/src/main/res/values/colors.xml b/samples/MegaDrone/src/main/res/values/colors.xml
new file mode 100644
index 0000000..69b2233
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="colorPrimary">#008577</color>
+    <color name="colorPrimaryDark">#00574B</color>
+    <color name="colorAccent">#D81B60</color>
+</resources>
diff --git a/samples/MegaDrone/src/main/res/values/strings.xml b/samples/MegaDrone/src/main/res/values/strings.xml
new file mode 100644
index 0000000..d13fb4c
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+    <string name="app_name">Mega Drone</string>
+</resources>
diff --git a/samples/MegaDrone/src/main/res/values/styles.xml b/samples/MegaDrone/src/main/res/values/styles.xml
new file mode 100644
index 0000000..5885930
--- /dev/null
+++ b/samples/MegaDrone/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+</resources>