Adding MegaDrone sample (from AES talk)
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