Merge branch 'master' into flowgraph
diff --git a/apps/OboeTester/app/src/main/cpp/AudioProcessorBase.cpp b/apps/OboeTester/app/src/main/cpp/AudioProcessorBase.cpp
deleted file mode 100644
index 3d9d012..0000000
--- a/apps/OboeTester/app/src/main/cpp/AudioProcessorBase.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2015 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.
- */
-/*
- * AudioProcessor.h
- *
- * Processing node in an audio graph.
- */
-#include <sys/types.h>
-#define MODULE_NAME "NatRingMole"
-#include "common/OboeDebug.h"
-#include "oboe/Oboe.h"
-#include "AudioProcessorBase.h"
-
-AudioPort::AudioPort(AudioProcessorBase &parent, int samplesPerFrame)
- : mParent(parent)
- , mSamplesPerFrame(samplesPerFrame) {
-}
-
-AudioFloatPort::AudioFloatPort(AudioProcessorBase &parent, int samplesPerFrame)
- : AudioPort(parent, samplesPerFrame), mFloatBuffer(NULL) {
- int numFloats = MAX_BLOCK_SIZE * mSamplesPerFrame;
- mFloatBuffer = new float[numFloats]{};
-}
-
-AudioFloatPort::~AudioFloatPort() {
- delete[] mFloatBuffer;
-}
-
-float *AudioFloatPort::getFloatBuffer(int numFrames) {
- assert(numFrames <= MAX_BLOCK_SIZE);
- return mFloatBuffer;
-}
-
-AudioOutputPort::AudioOutputPort(AudioProcessorBase &parent, int samplesPerFrame)
- : AudioFloatPort(parent, samplesPerFrame)
-{
- LOGD("AudioOutputPort(%d)", samplesPerFrame);
-}
-
-AudioResult AudioOutputPort::pullData(
- uint64_t framePosition,
- int numFrames) {
- return mParent.pullData(framePosition, numFrames);
-}
-
-void AudioOutputPort::connect(AudioInputPort *port) {
- port->connect(this);
-}
-void AudioOutputPort::disconnect(AudioInputPort *port) {
- port->disconnect(this);
-}
-
-AudioInputPort::AudioInputPort(AudioProcessorBase &parent, int samplesPerFrame)
- : AudioFloatPort(parent, samplesPerFrame)
-{
-}
-
-AudioResult AudioInputPort::pullData(
- uint64_t framePosition,
- int numFrames) {
- return (mConnected == nullptr)
- ? AUDIO_RESULT_SUCCESS
- : mConnected->pullData(framePosition, numFrames);
-}
-
-float *AudioInputPort::getFloatBuffer(int numFrames) {
- if (mConnected == NULL) {
- return AudioFloatPort::getFloatBuffer(numFrames);
- } else {
- return mConnected->getFloatBuffer(numFrames);
- }
-}
-
-void AudioInputPort::setValue(float value) {
- int numFloats = MAX_BLOCK_SIZE * mSamplesPerFrame;
- for (int i = 0; i < numFloats; i++) {
- mFloatBuffer[i] = value;
- }
-}
-
-/*
- * AudioProcessorBase
- */
-
-AudioResult AudioProcessorBase::pullData(
- uint64_t framePosition,
- int numFrames) {
- if (framePosition > mLastFramePosition) {
- mLastFramePosition = framePosition;
- mPreviousResult = onProcess(framePosition, numFrames);
- }
- return mPreviousResult;
-}
diff --git a/apps/OboeTester/app/src/main/cpp/AudioProcessorBase.h b/apps/OboeTester/app/src/main/cpp/AudioProcessorBase.h
deleted file mode 100644
index 5cd4cd3..0000000
--- a/apps/OboeTester/app/src/main/cpp/AudioProcessorBase.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2015 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.
- */
-/*
- * AudioProcessor.h
- *
- * Processing node in an audio graph.
- */
-
-#ifndef AUDIOPROCESSOR_H_
-#define AUDIOPROCESSOR_H_
-
-#include <cassert>
-#include <cstring>
-#include <math.h>
-#include <jni.h>
-#include <unistd.h>
-#include <time.h>
-
-#include <sys/types.h>
-
-#define MAX_BLOCK_SIZE 2048
-
-class AudioProcessorBase;
-
-class AudioInputPort;
-
-typedef int32_t AudioResult;
-#define AUDIO_RESULT_SUCCESS 0
-#define AUDIO_RESULT_FAIL -100
-
-
-class AudioPort {
-public:
- AudioPort(AudioProcessorBase &mParent, int samplesPerFrame);
-
- int getSamplesPerFrame() const { return mSamplesPerFrame; }
-
-protected:
- AudioProcessorBase &mParent;
- int mSamplesPerFrame;
-};
-
-class AudioFloatPort : public AudioPort {
-public:
- AudioFloatPort(AudioProcessorBase &mParent, int samplesPerFrame);
-
- virtual ~AudioFloatPort();
-
- virtual float *getFloatBuffer(int numFrames);
-
-protected:
- float *mFloatBuffer;
-};
-
-class AudioOutputPort : public AudioFloatPort {
-public:
- AudioOutputPort(AudioProcessorBase &parent, int samplesPerFrame);
-
- virtual ~AudioOutputPort() = default;
-
- using AudioFloatPort::getFloatBuffer;
-
- AudioResult pullData(
- uint64_t framePosition,
- int numFrames);
-
- void connect(AudioInputPort *port);
- void disconnect(AudioInputPort *port);
-};
-
-class AudioInputPort : public AudioFloatPort {
-public:
- AudioInputPort(AudioProcessorBase &parent, int mSamplesPerFrame);
-
- virtual ~AudioInputPort() = default;
-
- float *getFloatBuffer(int numFrames);
-
- AudioResult pullData(
- uint64_t framePosition,
- int numFrames);
-
- void connect(AudioOutputPort *port) {
- assert(getSamplesPerFrame() == port->getSamplesPerFrame());
- mConnected = port;
- }
- void disconnect(AudioOutputPort *port) {
- assert(mConnected == port);
- mConnected = NULL;
- }
- void disconnect() {
- mConnected = NULL;
- }
-
- void setValue(float value);
-
-private:
- AudioOutputPort *mConnected = nullptr;
-};
-
-
-class IAudioProcessor {
-public:
- virtual AudioResult onProcess(
- uint64_t framePosition,
- int numFrames) = 0;
-};
-
-class AudioProcessorBase : public IAudioProcessor {
-public:
- virtual ~AudioProcessorBase() = default;
-
- virtual AudioResult onProcess(
- uint64_t framePosition,
- int numFrames) = 0;
-
- AudioResult pullData(
- uint64_t framePosition,
- int numFrames);
-
- virtual void start() {
- mLastFramePosition = 0;
- }
-
- virtual void stop() {}
-
-private:
- uint64_t mLastFramePosition = 0;
- AudioResult mPreviousResult = AUDIO_RESULT_SUCCESS;
-};
-
-#endif /* AUDIOPROCESSOR_H_ */
diff --git a/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.cpp b/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.cpp
index f67a5d7..2a3e204 100644
--- a/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.cpp
+++ b/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.cpp
@@ -21,9 +21,9 @@
#include "oboe/Oboe.h"
#include "AudioStreamGateway.h"
+using namespace flowgraph;
+
AudioStreamGateway::AudioStreamGateway(int samplesPerFrame)
- : input(*this, samplesPerFrame)
- , mFramePosition(0)
{
}
@@ -35,60 +35,17 @@
oboe::AudioStream *audioStream,
void *audioData,
int numFrames) {
- int framesLeft = numFrames;
- int16_t *shortData = (int16_t *) audioData;
- float *floatData = (float *) audioData;
- AudioResult result = 0;
-
-#ifdef OBOE_TESTER_DEBUG_STOP
- if (mFrameCountdown <= 0) {
- LOGI("%s() : mCallCounter = %d\n", __func__, mCallCounter);
- mFrameCountdown = 4800;
- }
- mFrameCountdown -= numFrames;
- mCallCounter++;
- if (mCallCounter > 500) {
- LOGI("%s() : return STOP\n", __func__);
- return oboe::DataCallbackResult::Stop;
- }
-#endif /* OBOE_TESTER_DEBUG_STOP */
if (!mSchedulerChecked) {
mScheduler = sched_getscheduler(gettid());
mSchedulerChecked = true;
}
- while (framesLeft > 0) {
- // Do not process more than the MAX block size in one pass.
- int framesToPlay = framesLeft;
- if (framesToPlay > MAX_BLOCK_SIZE) {
- framesToPlay = MAX_BLOCK_SIZE;
- }
- // Run the graph and pull data through the input port.
- result = onProcess(mFramePosition, framesToPlay);
- if (result < 0) {
- break;
- }
- const float *signal = input.getFloatBuffer(framesToPlay);
- int32_t numSamples = framesToPlay * input.getSamplesPerFrame();
- if (audioStream->getFormat() == oboe::AudioFormat::I16) {
- oboe::convertFloatToPcm16(signal, shortData, numSamples);
- shortData += numSamples;
- } else if (audioStream->getFormat() == oboe::AudioFormat::Float) {
- memcpy(floatData, signal, numSamples * sizeof(float));
- floatData += numSamples;
- }
- mFramePosition += framesToPlay;
- framesLeft -= framesToPlay;
+ if (mAudioSink != nullptr) {
+ mAudioSink->read(audioData, numFrames);
}
- return (result < 0) ? oboe::DataCallbackResult::Stop : oboe::DataCallbackResult::Continue;
-}
-AudioResult AudioStreamGateway::onProcess(
- uint64_t framePosition,
- int numFrames) {
- AudioResult result = input.pullData(framePosition, numFrames);
- return result;
+ return oboe::DataCallbackResult::Continue;
}
int AudioStreamGateway::getScheduler() {
diff --git a/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.h b/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.h
index fe22b50..09d69c6 100644
--- a/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.h
+++ b/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.h
@@ -19,28 +19,24 @@
#include <unistd.h>
#include <sys/types.h>
-#include "AudioProcessorBase.h"
+#include "flowgraph/AudioProcessorBase.h"
#include "oboe/Oboe.h"
+using namespace flowgraph;
+
/**
* Bridge between an audio graph and an audio device.
- * Connect the audio units to the "input" and then pass
+ * Pass in an AudioSink and then pass
* this object to the AudioStreamBuilder as a callback.
*/
-class AudioStreamGateway : public AudioProcessorBase, public oboe::AudioStreamCallback {
+class AudioStreamGateway : public oboe::AudioStreamCallback {
public:
AudioStreamGateway(int samplesPerFrame);
virtual ~AudioStreamGateway();
- /**
- * Process audio for the graph.
- * @param framePosition
- * @param numFrames
- * @return
- */
- AudioResult onProcess(
- uint64_t framePosition,
- int numFrames) override;
+ void setAudioSink(std::shared_ptr<flowgraph::AudioSink> sink) {
+ mAudioSink = sink;
+ }
/**
* Called by Oboe when the stream is ready to process audio.
@@ -50,23 +46,13 @@
void *audioData,
int numFrames) override;
- AudioInputPort input;
-
int getScheduler();
- void start() override {
- AudioProcessorBase::start();
- mCallCounter = 0;
- mFrameCountdown = 0;
- }
-
private:
- uint64_t mFramePosition;
+ // TODO uint64_t mFramePosition;
bool mSchedulerChecked = false;
int mScheduler;
-
- int32_t mCallCounter = 0;
- int32_t mFrameCountdown = 0;
+ std::shared_ptr<flowgraph::AudioSink> mAudioSink;
};
diff --git a/apps/OboeTester/app/src/main/cpp/FifoProcessor.cpp b/apps/OboeTester/app/src/main/cpp/FifoProcessor.cpp
deleted file mode 100644
index f7478bf..0000000
--- a/apps/OboeTester/app/src/main/cpp/FifoProcessor.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 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 "FifoProcessor.h"
-
-
-FifoProcessor::FifoProcessor(int channelCount, int numFrames, int threshold)
- : mFifoBuffer(channelCount, numFrames)
- , output(*this, channelCount)
-{
- mFifoBuffer.setThresholdFrames(threshold);
-}
-
-FifoProcessor::~FifoProcessor() {
-}
diff --git a/apps/OboeTester/app/src/main/cpp/FifoProcessor.h b/apps/OboeTester/app/src/main/cpp/FifoProcessor.h
deleted file mode 100644
index a562b79..0000000
--- a/apps/OboeTester/app/src/main/cpp/FifoProcessor.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 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 NATIVEOBOE_FIFIPROCESSOR_H
-#define NATIVEOBOE_FIFIPROCESSOR_H
-
-#include "AudioProcessorBase.h"
-#include "fifo/FifoBuffer.h"
-
-class FifoProcessor : public AudioProcessorBase {
-public:
- FifoProcessor(int samplesPerFrame, int numFrames, int threshold);
-
- virtual ~FifoProcessor();
-
- uint32_t read(float *destination, int framesToRead) {
- return mFifoBuffer.read(destination, framesToRead);
- }
-
- uint32_t write(const float *source, int framesToWrite) {
- return mFifoBuffer.write(source, framesToWrite);
- }
-
- uint32_t getThresholdFrames() {
- return mFifoBuffer.getThresholdFrames();
- }
-
- void setThresholdFrames(uint32_t threshold) {
- return mFifoBuffer.setThresholdFrames(threshold);
- }
-
- AudioResult onProcess(
- uint64_t framePosition,
- int numFrames) override {
- float *buffer = output.getFloatBuffer(numFrames);
- return mFifoBuffer.readNow(buffer, numFrames);
- }
-
- uint32_t getUnderrunCount() const { return mFifoBuffer.getUnderrunCount(); }
-
-private:
- oboe::FifoBuffer mFifoBuffer;
-
-public:
- AudioOutputPort output;
-
-};
-
-
-#endif //NATIVEOBOE_FIFIPROCESSOR_H
diff --git a/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.h b/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.h
index ddcce09..fd0aee0 100644
--- a/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.h
+++ b/apps/OboeTester/app/src/main/cpp/InputStreamCallbackAnalyzer.h
@@ -21,7 +21,7 @@
#include <unistd.h>
#include <sys/types.h>
-#include "AudioProcessorBase.h"
+// TODO #include "flowgraph/AudioProcessorBase.h"
#include "oboe/Oboe.h"
#include "MultiChannelRecording.h"
#include "PeakDetector.h"
diff --git a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp
index 3ec5f3c..72216de 100644
--- a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp
+++ b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp
@@ -20,7 +20,8 @@
NativeAudioContext::NativeAudioContext()
- : sineGenerators(MAX_SINE_OSCILLATORS) {
+ : sineOscillators(MAX_SINE_OSCILLATORS)
+ , sawtoothOscillators(MAX_SINE_OSCILLATORS) {
}
void NativeAudioContext::close() {
@@ -34,6 +35,8 @@
manyToMulti.reset(nullptr);
monoToMulti.reset(nullptr);
audioStreamGateway.reset(nullptr);
+ mSinkFloat.reset();
+ mSinkI16.reset();
}
bool NativeAudioContext::isMMapUsed() {
@@ -65,17 +68,27 @@
switch (mToneType) {
case ToneType::SawPing:
sawPingGenerator.output.connect(&(monoToMulti->input));
- monoToMulti->output.connect(&(audioStreamGateway.get()->input));
+ monoToMulti->output.connect(&(mSinkFloat.get()->input));
+ monoToMulti->output.connect(&(mSinkI16.get()->input));
break;
case ToneType::Sine:
for (int i = 0; i < mChannelCount; i++) {
- sineGenerators[i].output.connect(manyToMulti->inputs[i].get());
+ sineOscillators[i].output.connect(manyToMulti->inputs[i].get());
}
- manyToMulti->output.connect(&(audioStreamGateway.get()->input));
+ manyToMulti->output.connect(&(mSinkFloat.get()->input));
+ manyToMulti->output.connect(&(mSinkI16.get()->input));
break;
case ToneType::Impulse:
impulseGenerator.output.connect(&(monoToMulti->input));
- monoToMulti->output.connect(&(audioStreamGateway.get()->input));
+ monoToMulti->output.connect(&(mSinkFloat.get()->input));
+ monoToMulti->output.connect(&(mSinkI16.get()->input));
+ break;
+ case ToneType::Sawtooth:
+ for (int i = 0; i < mChannelCount; i++) {
+ sawtoothOscillators[i].output.connect(manyToMulti->inputs[i].get());
+ }
+ manyToMulti->output.connect(&(mSinkFloat.get()->input));
+ manyToMulti->output.connect(&(mSinkI16.get()->input));
break;
}
}
@@ -86,7 +99,16 @@
return;
}
if (enabled) {
- sineGenerators[channelIndex].output.connect(manyToMulti->inputs[channelIndex].get());
+ switch (mToneType) {
+ case ToneType::Sine:
+ sineOscillators[channelIndex].output.connect(manyToMulti->inputs[channelIndex].get());
+ break;
+ case ToneType::Sawtooth:
+ sawtoothOscillators[channelIndex].output.connect(manyToMulti->inputs[channelIndex].get());
+ break;
+ default:
+ break;
+ }
} else {
manyToMulti->inputs[channelIndex]->disconnect();
}
@@ -152,10 +174,16 @@
} else {
double frequency = 440.0;
for (int i = 0; i < mChannelCount; i++) {
- sineGenerators[i].setSampleRate(oboeStream->getSampleRate());
- sineGenerators[i].frequency.setValue(frequency);
- frequency *= 4.0 / 3.0; // each sine is a higher frequency
- sineGenerators[i].amplitude.setValue(AMPLITUDE_SINE);
+ sineOscillators[i].setSampleRate(oboeStream->getSampleRate());
+ sineOscillators[i].frequency.setValue(frequency);
+ frequency *= 4.0 / 3.0; // each sine is at a higher frequency
+ sineOscillators[i].amplitude.setValue(AMPLITUDE_SINE);
+ }
+ for (int i = 0; i < mChannelCount; i++) {
+ sawtoothOscillators[i].setSampleRate(oboeStream->getSampleRate());
+ sawtoothOscillators[i].frequency.setValue(frequency);
+ frequency *= 4.0 / 3.0; // each sawtooth is at a higher frequency
+ sawtoothOscillators[i].amplitude.setValue(AMPLITUDE_SAWTOOTH);
}
impulseGenerator.setSampleRate(oboeStream->getSampleRate());
@@ -169,9 +197,17 @@
manyToMulti = std::make_unique<ManyToMultiConverter>(mChannelCount);
monoToMulti = std::make_unique<MonoToMultiConverter>(mChannelCount);
+ mSinkFloat = std::make_unique<SinkFloat>(mChannelCount);
+ mSinkI16 = std::make_unique<SinkI16>(mChannelCount);
+
// We needed the proxy because we did not know the channelCount
// when we setup the Builder.
audioStreamGateway = std::make_unique<AudioStreamGateway>(mChannelCount);
+ if (oboeStream->getFormat() == oboe::AudioFormat::I16) {
+ audioStreamGateway->setAudioSink(mSinkI16);
+ } else if (oboeStream->getFormat() == oboe::AudioFormat::Float) {
+ audioStreamGateway->setAudioSink(mSinkFloat);
+ }
connectTone();
diff --git a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h
index df6ac36..4d389ea 100644
--- a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h
+++ b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h
@@ -18,6 +18,7 @@
#define NATIVEOBOE_NATIVEAUDIOCONTEXT_H
#include <dlfcn.h>
+#include <jni.h>
#include <thread>
#include <vector>
@@ -25,20 +26,24 @@
#include "oboe/Oboe.h"
#include "AudioStreamGateway.h"
-#include "ImpulseGenerator.h"
+#include "flowgraph/ImpulseOscillator.h"
+#include "flowgraph/ManyToMultiConverter.h"
+#include "flowgraph/MonoToMultiConverter.h"
+#include "flowgraph/SinkFloat.h"
+#include "flowgraph/SinkI16.h"
+#include "flowgraph/SineOscillator.h"
+#include "flowgraph/SawtoothOscillator.h"
#include "InputStreamCallbackAnalyzer.h"
-#include "ManyToMultiConverter.h"
-#include "MonoToMultiConverter.h"
#include "MultiChannelRecording.h"
#include "OboeStreamCallbackProxy.h"
#include "PlayRecordingCallback.h"
#include "SawPingGenerator.h"
-#include "SineGenerator.h"
#define MAX_SINE_OSCILLATORS 8
#define AMPLITUDE_SINE 1.0
+#define AMPLITUDE_SAWTOOTH 0.5
#define FREQUENCY_SAW_PING 800.0
-#define AMPLITUDE_SAW_PING 1.0
+#define AMPLITUDE_SAW_PING 0.8
#define AMPLITUDE_IMPULSE 0.7
#define NANOS_PER_MICROSECOND ((int64_t) 1000)
@@ -109,6 +114,7 @@
result = oboeStream->requestStop();
printScheduler();
}
+ LOGD("NativeAudioContext::%s() returns %d", __func__, result);
return result;
}
@@ -129,15 +135,24 @@
oboe::Result result1 = stopPlayback();
oboe::Result result2 = stopAudio();
+ LOGD("NativeAudioContext::%s() stop modules", __func__);
for (int i = 0; i < mChannelCount; i++) {
- sineGenerators[i].stop();
+ sineOscillators[i].stop();
+ sawtoothOscillators[i].stop();
}
impulseGenerator.stop();
sawPingGenerator.stop();
- if (audioStreamGateway != nullptr) {
- audioStreamGateway->stop();
+ if (mSinkFloat) {
+ mSinkFloat->stop();
}
- return (result1 != oboe::Result::OK) ? result1 : result2;
+ if (mSinkI16) {
+ mSinkI16->stop();
+ }
+
+ oboe::Result result = (result1 != oboe::Result::OK) ? result1 : result2;
+
+ LOGD("NativeAudioContext::%s() returns %d", __func__, result);
+ return result;
}
oboe::Result startPlayback() {
@@ -171,22 +186,30 @@
}
oboe::Result start() {
+
+ LOGD("NativeAudioContext: %s() called", __func__);
+
if (oboeStream == nullptr) {
return oboe::Result::ErrorInvalidState;
}
stop();
+ LOGD("NativeAudioContext: %s() start modules", __func__);
for (int i = 0; i < mChannelCount; i++) {
- sineGenerators[i].start();
+ sineOscillators[i].start();
+ sawtoothOscillators[i].start();
}
impulseGenerator.start();
sawPingGenerator.start();
- if (audioStreamGateway != nullptr) {
- audioStreamGateway->start();
+ if (mSinkFloat) {
+ mSinkFloat->start();
+ }
+ if (mSinkI16) {
+ mSinkI16->start();
}
- LOGD("OboeAudioStream_start: start called");
+ LOGD("NativeAudioContext: %s start stream", __func__);
oboe::Result result = oboe::Result::OK;
if (oboeStream != nullptr) {
result = oboeStream->requestStart();
@@ -216,7 +239,8 @@
void setAmplitude(double amplitude) {
LOGD("%s(%f)", __func__, amplitude);
for (int i = 0; i < mChannelCount; i++) {
- sineGenerators[i].amplitude.setValue(amplitude);
+ sineOscillators[i].amplitude.setValue(amplitude);
+ sawtoothOscillators[i].amplitude.setValue(amplitude);
}
sawPingGenerator.amplitude.setValue(amplitude);
impulseGenerator.amplitude.setValue(amplitude);
@@ -245,7 +269,8 @@
enum ToneType {
SawPing = 0,
Sine = 1,
- Impulse = 2
+ Impulse = 2,
+ Sawtooth = 3
};
void connectTone();
@@ -274,15 +299,18 @@
std::thread *dataThread = nullptr;
OboeStreamCallbackProxy oboeCallbackProxy;
- std::vector<SineGenerator> sineGenerators;
+ std::vector<SineOscillator> sineOscillators;
+ std::vector<SawtoothOscillator> sawtoothOscillators;
- ImpulseGenerator impulseGenerator;
+ ImpulseOscillator impulseGenerator;
SawPingGenerator sawPingGenerator;
oboe::AudioStream *playbackStream = nullptr;
std::unique_ptr<float []> dataBuffer{};
std::unique_ptr<ManyToMultiConverter> manyToMulti;
std::unique_ptr<MonoToMultiConverter> monoToMulti;
+ std::shared_ptr<flowgraph::SinkFloat> mSinkFloat;
+ std::shared_ptr<flowgraph::SinkI16> mSinkI16;
std::unique_ptr<AudioStreamGateway> audioStreamGateway{};
std::unique_ptr<MultiChannelRecording> mRecording{};
diff --git a/apps/OboeTester/app/src/main/cpp/OscillatorBase.h b/apps/OboeTester/app/src/main/cpp/OscillatorBase.h
deleted file mode 100644
index cf2a605..0000000
--- a/apps/OboeTester/app/src/main/cpp/OscillatorBase.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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 NATIVEOBOE_OSCILLATORBASE_H
-#define NATIVEOBOE_OSCILLATORBASE_H
-
-#include "AudioProcessorBase.h"
-
-constexpr float TWO_PI = (float)(2.0 * M_PI);
-
-class OscillatorBase : public AudioProcessorBase {
-public:
- OscillatorBase();
-
- virtual ~OscillatorBase() = default;
-
- void setSampleRate(float sampleRate) {
- mSampleRate = sampleRate;
- mFrequencyToPhase = TWO_PI / sampleRate; // scaler
- }
-
- float setSampleRate() {
- return mSampleRate;
- }
-
- AudioInputPort frequency;
- AudioInputPort amplitude;
- AudioOutputPort output;
-
-protected:
- float incrementPhase(float frequency) {
- mPhase += frequency * mFrequencyToPhase;
- if (mPhase >= TWO_PI) {
- mPhase -= TWO_PI;
- } else if (mPhase < 0) {
- mPhase += TWO_PI;
- }
- return mPhase;
- }
-
- float mPhase = 0.0;
- float mSampleRate;
- float mFrequencyToPhase;
-};
-
-
-#endif //NATIVEOBOE_OSCILLATORBASE_H
diff --git a/apps/OboeTester/app/src/main/cpp/SawPingGenerator.cpp b/apps/OboeTester/app/src/main/cpp/SawPingGenerator.cpp
index 01f4dcf..6b128c0 100644
--- a/apps/OboeTester/app/src/main/cpp/SawPingGenerator.cpp
+++ b/apps/OboeTester/app/src/main/cpp/SawPingGenerator.cpp
@@ -15,9 +15,10 @@
*/
#include <unistd.h>
-#include "AudioProcessorBase.h"
-#include "SawPingGenerator.h"
#include "oboe/Definitions.h"
+#include "SawPingGenerator.h"
+
+using namespace flowgraph;
SawPingGenerator::SawPingGenerator()
: OscillatorBase()
@@ -28,18 +29,16 @@
SawPingGenerator::~SawPingGenerator() { }
-
-AudioResult SawPingGenerator::onProcess(
- uint64_t framePosition,
+int32_t SawPingGenerator::onProcess(
+ int64_t framePosition,
int numFrames) {
frequency.pullData(framePosition, numFrames);
amplitude.pullData(framePosition, numFrames);
- const float *frequencies = frequency.getFloatBuffer(numFrames);
- const float *amplitudes = amplitude.getFloatBuffer(numFrames);
- float *buffer = output.getFloatBuffer(numFrames);
-
+ const float *frequencies = frequency.getBlock();
+ const float *amplitudes = amplitude.getBlock();
+ float *buffer = output.getBlock();
if (mRequestCount.load() > mAcknowledgeCount.load()) {
mPhase = -1.0f;
@@ -60,7 +59,7 @@
}
}
- return AUDIO_RESULT_SUCCESS;
+ return numFrames;
}
void SawPingGenerator::setEnabled(bool enabled) {
diff --git a/apps/OboeTester/app/src/main/cpp/SawPingGenerator.h b/apps/OboeTester/app/src/main/cpp/SawPingGenerator.h
index c51387e..05bb745 100644
--- a/apps/OboeTester/app/src/main/cpp/SawPingGenerator.h
+++ b/apps/OboeTester/app/src/main/cpp/SawPingGenerator.h
@@ -21,8 +21,8 @@
#include <unistd.h>
#include <sys/types.h>
-#include "AudioProcessorBase.h"
-#include "OscillatorBase.h"
+#include "flowgraph/AudioProcessorBase.h"
+#include "flowgraph/OscillatorBase.h"
class SawPingGenerator : public OscillatorBase {
public:
@@ -30,8 +30,8 @@
virtual ~SawPingGenerator();
- AudioResult onProcess(
- uint64_t framePosition,
+ int32_t onProcess(
+ int64_t framePosition,
int numFrames) override;
void setEnabled(bool enabled);
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.cpp
new file mode 100644
index 0000000..5667fdb
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2015 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 <algorithm>
+#include <sys/types.h>
+#include "AudioProcessorBase.h"
+
+using namespace flowgraph;
+
+/***************************************************************************/
+int32_t AudioProcessorBase::pullData(int64_t framePosition, int32_t numFrames) {
+ if (framePosition > mLastFramePosition) {
+ mLastFramePosition = framePosition;
+ mFramesValid = onProcess(framePosition, numFrames);
+ }
+ return mFramesValid;
+}
+
+/***************************************************************************/
+AudioFloatBlockPort::AudioFloatBlockPort(AudioProcessorBase &parent,
+ int32_t samplesPerFrame,
+ int32_t framesPerBlock)
+ : AudioPort(parent, samplesPerFrame)
+ , mFramesPerBlock(framesPerBlock)
+ , mSampleBlock(NULL) {
+ int32_t numFloats = framesPerBlock * getSamplesPerFrame();
+ mSampleBlock = new float[numFloats]{0.0f};
+}
+
+AudioFloatBlockPort::~AudioFloatBlockPort() {
+ delete[] mSampleBlock;
+}
+
+/***************************************************************************/
+int32_t AudioFloatOutputPort::pullData(int64_t framePosition, int32_t numFrames) {
+ numFrames = std::min(getFramesPerBlock(), numFrames);
+ return mParent.pullData(framePosition, numFrames);
+}
+
+// These need to be in the .cpp file because of forward cross references.
+void AudioFloatOutputPort::connect(AudioFloatInputPort *port) {
+ port->connect(this);
+}
+
+void AudioFloatOutputPort::disconnect(AudioFloatInputPort *port) {
+ port->disconnect(this);
+}
+
+/***************************************************************************/
+int32_t AudioFloatInputPort::pullData(int64_t framePosition, int32_t numFrames) {
+ return (mConnected == NULL)
+ ? std::min(getFramesPerBlock(), numFrames)
+ : mConnected->pullData(framePosition, numFrames);
+}
+
+float *AudioFloatInputPort::getBlock() {
+ if (mConnected == NULL) {
+ return AudioFloatBlockPort::getBlock(); // loaded using setValue()
+ } else {
+ return mConnected->getBlock();
+ }
+}
+
+/***************************************************************************/
+int32_t AudioSink::pull(int32_t numFrames) {
+ int32_t actualFrames = input.pullData(mFramePosition, numFrames);
+ mFramePosition += actualFrames;
+ return actualFrames;
+}
\ No newline at end of file
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.h b/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.h
new file mode 100644
index 0000000..3c5fe4d
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.h
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2015 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.
+ */
+
+/*
+ * AudioProcessorBase.h
+ *
+ * Audio processing node and ports that can be used in a simple data flow graph.
+ */
+
+#ifndef FLOWGRAPH_AUDIO_PROCESSOR_BASE_H
+#define FLOWGRAPH_AUDIO_PROCESSOR_BASE_H
+
+#include <cassert>
+#include <cstring>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+// Set this to 1 if using it inside the Android framework.
+#define FLOWGRAPH_ANDROID_INTERNAL 0
+
+namespace flowgraph {
+
+// Default block size that can be overridden when the AudioFloatBlockPort is created.
+// If it is too small then we will have too much overhead from switching between nodes.
+// If it is too high then we will thrash the caches.
+constexpr int kDefaultBlockSize = 8; // arbitrary
+
+class AudioFloatInputPort;
+
+/***************************************************************************/
+class AudioProcessorBase {
+public:
+ virtual ~AudioProcessorBase() = default;
+
+ /**
+ * Perform custom function.
+ *
+ * @param framePosition index of first frame to be processed
+ * @param numFrames maximum number of frames requested for processing
+ * @return number of frames actually processed
+ */
+ virtual int32_t onProcess(int64_t framePosition, int32_t numFrames) = 0;
+
+ /**
+ * If the framePosition is at or after the last frame position then call onProcess().
+ * This prevents infinite recursion in case of cyclic graphs.
+ * It also prevents nodes upstream from a branch from being executed twice.
+ *
+ * @param framePosition
+ * @param numFrames
+ * @return number of frames valid
+ */
+ int32_t pullData(int64_t framePosition, int32_t numFrames);
+
+ virtual void start() {
+ mLastFramePosition = 0;
+ }
+
+ virtual void stop() {}
+
+protected:
+ int64_t mLastFramePosition = -1; // Start at -1 so that the first pull works.
+
+private:
+ int32_t mFramesValid = 0; // num valid frames in the block
+};
+
+/***************************************************************************/
+/**
+ * This is a connector that allows data to flow between modules.
+ *
+ * The ports are the primary means of interacting with a module.
+ * So they are generally declared as public.
+ *
+ */
+class AudioPort {
+public:
+ AudioPort(AudioProcessorBase &parent, int32_t samplesPerFrame)
+ : mParent(parent)
+ , mSamplesPerFrame(samplesPerFrame) {
+ }
+
+ // Ports are often declared public. So let's make them non-copyable.
+ AudioPort(const AudioPort&) = delete;
+ AudioPort& operator=(const AudioPort&) = delete;
+
+ int32_t getSamplesPerFrame() const {
+ return mSamplesPerFrame;
+ }
+
+protected:
+ AudioProcessorBase &mParent;
+
+private:
+ const int32_t mSamplesPerFrame = 1;
+};
+
+/***************************************************************************/
+/**
+ * This port contains a float type buffer.
+ * The size is framesPerBlock * samplesPerFrame).
+ */
+class AudioFloatBlockPort : public AudioPort {
+public:
+ AudioFloatBlockPort(AudioProcessorBase &mParent,
+ int32_t samplesPerFrame,
+ int32_t framesPerBlock = kDefaultBlockSize
+ );
+
+ virtual ~AudioFloatBlockPort();
+
+ int32_t getFramesPerBlock() const {
+ return mFramesPerBlock;
+ }
+
+protected:
+
+ /**
+ * @return buffer internal to the port or from a connected port
+ */
+ virtual float *getBlock() {
+ return mSampleBlock;
+ }
+
+
+private:
+ const int32_t mFramesPerBlock = 1;
+ float *mSampleBlock = nullptr; // allocated in constructor
+};
+
+/***************************************************************************/
+/**
+ * The results of a module are stored in the buffer of the output ports.
+ */
+class AudioFloatOutputPort : public AudioFloatBlockPort {
+public:
+ AudioFloatOutputPort(AudioProcessorBase &parent, int32_t samplesPerFrame)
+ : AudioFloatBlockPort(parent, samplesPerFrame) {
+ }
+
+ virtual ~AudioFloatOutputPort() = default;
+
+ using AudioFloatBlockPort::getBlock;
+
+ /**
+ * Call the parent module's onProcess() method.
+ * That may pull data from its inputs and recursively
+ * process the entire graph.
+ * @return number of frames actually pulled
+ */
+ int32_t pullData(int64_t framePosition, int32_t numFrames);
+
+ /**
+ * Connect to the input of another module.
+ * An input port can only have one connection.
+ * An output port can have multiple connections.
+ * If you connect a second output port to an input port
+ * then it overwrites the previous connection.
+ *
+ * This not thread safe. Do not modify the graph topology from another thread while running.
+ * Also do not delete a module while it is connected to another port if the graph is running.
+ */
+ void connect(AudioFloatInputPort *port);
+
+ /**
+ * Disconnect from the input of another module.
+ * This not thread safe.
+ */
+ void disconnect(AudioFloatInputPort *port);
+};
+
+/***************************************************************************/
+class AudioFloatInputPort : public AudioFloatBlockPort {
+public:
+ AudioFloatInputPort(AudioProcessorBase &parent, int32_t samplesPerFrame)
+ : AudioFloatBlockPort(parent, samplesPerFrame) {
+ }
+
+ virtual ~AudioFloatInputPort() = default;
+
+ /**
+ * If connected to an output port then this will return
+ * that output ports buffers.
+ * If not connected then it returns the input ports own buffer
+ * which can be loaded using setValue().
+ */
+ float *getBlock() override;
+
+ /**
+ * Pull data from any output port that is connected.
+ */
+ int32_t pullData(int64_t framePosition, int32_t numFrames);
+
+ /**
+ * Write every value of the float buffer.
+ * This value will be ignored if an output port is connected
+ * to this port.
+ */
+ void setValue(float value) {
+ int numFloats = kDefaultBlockSize * getSamplesPerFrame();
+ float *buffer = getBlock();
+ for (int i = 0; i < numFloats; i++) {
+ *buffer++ = value;
+ }
+ }
+
+ /**
+ * Connect to the output of another module.
+ * An input port can only have one connection.
+ * An output port can have multiple connections.
+ * This not thread safe.
+ */
+ void connect(AudioFloatOutputPort *port) {
+ assert(getSamplesPerFrame() == port->getSamplesPerFrame());
+ mConnected = port;
+ }
+
+ void disconnect(AudioFloatOutputPort *port) {
+ assert(mConnected == port);
+ (void) port;
+ mConnected = nullptr;
+ }
+
+ void disconnect() {
+ mConnected = nullptr;
+ }
+
+private:
+ AudioFloatOutputPort *mConnected = nullptr;
+};
+
+/***************************************************************************/
+class AudioSource : public AudioProcessorBase {
+public:
+ explicit AudioSource(int32_t channelCount)
+ : output(*this, channelCount) {
+ }
+
+ virtual ~AudioSource() = default;
+
+ AudioFloatOutputPort output;
+
+ void setData(const void *data, int32_t numFrames) {
+ mData = data;
+ mSizeInFrames = numFrames;
+ mFrameIndex = 0;
+ }
+
+protected:
+ const void *mData = nullptr;
+ int32_t mSizeInFrames = 0; // number of frames in mData
+ int32_t mFrameIndex = 0; // index of next frame to be processed
+};
+
+/***************************************************************************/
+class AudioSink : public AudioProcessorBase {
+public:
+ explicit AudioSink(int32_t channelCount)
+ : input(*this, channelCount) {
+ }
+
+ virtual ~AudioSink() = default;
+
+ AudioFloatInputPort input;
+
+ /**
+ * Dummy processor. The work happens in the read() method.
+ *
+ * @param framePosition index of first frame to be processed
+ * @param numFrames
+ * @return number of frames actually processed
+ */
+ int32_t onProcess(int64_t framePosition, int32_t numFrames) override {
+ (void) framePosition;
+ (void) numFrames;
+ return 0;
+ };
+
+ virtual int32_t read(void *data, int32_t numFrames) = 0;
+
+protected:
+ int32_t pull(int32_t numFrames);
+
+private:
+ int64_t mFramePosition = 0;
+};
+
+} /* namespace flowgraph */
+
+#endif /* FLOWGRAPH_AUDIO_PROCESSOR_BASE_H */
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.cpp
new file mode 100644
index 0000000..bd9c22a
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 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 <algorithm>
+#include <unistd.h>
+#include "AudioProcessorBase.h"
+#include "ClipToRange.h"
+
+using namespace flowgraph;
+
+ClipToRange::ClipToRange(int32_t channelCount)
+ : input(*this, channelCount)
+ , output(*this, channelCount) {
+}
+
+int32_t ClipToRange::onProcess(int64_t framePosition, int32_t numFrames) {
+ int32_t framesToProcess = input.pullData(framePosition, numFrames);
+ const float *inputBuffer = input.getBlock();
+ float *outputBuffer = output.getBlock();
+
+ int32_t numSamples = framesToProcess * output.getSamplesPerFrame();
+ for (int32_t i = 0; i < numSamples; i++) {
+ *outputBuffer++ = std::min(mMaximum, std::max(mMinimum, *inputBuffer++));
+ }
+
+ return framesToProcess;
+}
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.h b/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.h
new file mode 100644
index 0000000..9eef254
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015 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 FLOWGRAPH_CLIP_TO_RANGE_H
+#define FLOWGRAPH_CLIP_TO_RANGE_H
+
+#include <atomic>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "AudioProcessorBase.h"
+
+namespace flowgraph {
+
+// This is 3 dB, (10^(3/20)), to match the maximum headroom in AudioTrack for float data.
+// It is designed to allow occasional transient peaks.
+constexpr float kDefaultMaxHeadroom = 1.41253754f;
+constexpr float kDefaultMinHeadroom = -kDefaultMaxHeadroom;
+
+class ClipToRange : public AudioProcessorBase {
+public:
+ explicit ClipToRange(int32_t channelCount);
+
+ virtual ~ClipToRange() = default;
+
+ int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+
+ void setMinimum(float min) {
+ mMinimum = min;
+ }
+
+ float getMinimum() const {
+ return mMinimum;
+ }
+
+ void setMaximum(float min) {
+ mMaximum = min;
+ }
+
+ float getMaximum() const {
+ return mMaximum;
+ }
+
+ AudioFloatInputPort input;
+ AudioFloatOutputPort output;
+
+private:
+ float mMinimum = kDefaultMinHeadroom;
+ float mMaximum = kDefaultMaxHeadroom;
+};
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_CLIP_TO_RANGE_H
diff --git a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.cpp
similarity index 62%
rename from apps/OboeTester/app/src/main/cpp/ImpulseGenerator.cpp
rename to apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.cpp
index d621a8c..4847b4e 100644
--- a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.cpp
@@ -16,34 +16,33 @@
#include <math.h>
#include <unistd.h>
-#include "AudioProcessorBase.h"
-#include "ImpulseGenerator.h"
+#include "ImpulseOscillator.h"
-ImpulseGenerator::ImpulseGenerator()
+ImpulseOscillator::ImpulseOscillator()
: OscillatorBase() {
}
-AudioResult ImpulseGenerator::onProcess(
- uint64_t framePosition,
+int32_t ImpulseOscillator::onProcess(
+ int64_t framePosition,
int numFrames) {
frequency.pullData(framePosition, numFrames);
amplitude.pullData(framePosition, numFrames);
- const float *frequencies = frequency.getFloatBuffer(numFrames);
- const float *amplitudes = amplitude.getFloatBuffer(numFrames);
- float *buffer = output.getFloatBuffer(numFrames);
+ const float *frequencies = frequency.getBlock();
+ const float *amplitudes = amplitude.getBlock();
+ float *buffer = output.getBlock();
for (int i = 0; i < numFrames; i++) {
float value = 0.0f;
- mPhase += mFrequencyToPhase * frequencies[i];
- if (mPhase >= TWO_PI) {
- value = amplitudes[i];
- mPhase -= TWO_PI;
+ mPhase += mFrequencyToPhaseIncrement * frequencies[i];
+ if (mPhase >= 1.0f) {
+ value = amplitudes[i]; // spike
+ mPhase -= 2.0f;
}
*buffer++ = value;
}
- return AUDIO_RESULT_SUCCESS;
+ return numFrames;
}
diff --git a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h b/apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.h
similarity index 70%
rename from apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
rename to apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.h
index 5db11b5..2492c1f 100644
--- a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.h
@@ -23,16 +23,19 @@
#include "AudioProcessorBase.h"
#include "OscillatorBase.h"
-class ImpulseGenerator : public OscillatorBase {
+/**
+ * Generate a raw impulse equal to the amplitude.
+ * The output baseline is zero.
+ *
+ * The waveform is not band-limited so it will have aliasing artifacts at higher frequencies.
+ */
+class ImpulseOscillator : public OscillatorBase {
public:
- ImpulseGenerator();
+ ImpulseOscillator();
- AudioResult onProcess(
- uint64_t framePosition,
- int numFrames);
-
-
-
+ int32_t onProcess(
+ int64_t framePosition,
+ int numFrames) override;
};
#endif //NATIVEOBOE_IMPULSE_GENERATOR_H
diff --git a/apps/OboeTester/app/src/main/cpp/ManyToMultiConverter.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.cpp
similarity index 79%
rename from apps/OboeTester/app/src/main/cpp/ManyToMultiConverter.cpp
rename to apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.cpp
index ba5ad9f..a17ad93 100644
--- a/apps/OboeTester/app/src/main/cpp/ManyToMultiConverter.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.cpp
@@ -15,19 +15,21 @@
*/
#include <unistd.h>
-#include "AudioProcessorBase.h"
+
#include "ManyToMultiConverter.h"
+using namespace flowgraph;
+
ManyToMultiConverter::ManyToMultiConverter(int32_t channelCount)
: inputs(channelCount)
, output(*this, channelCount) {
for (int i = 0; i < channelCount; i++) {
- inputs[i] = std::make_unique<AudioInputPort>(*this, 1);
+ inputs[i] = std::make_unique<AudioFloatInputPort>(*this, 1);
}
}
-AudioResult ManyToMultiConverter::onProcess(
- uint64_t framePosition,
+int32_t ManyToMultiConverter::onProcess(
+ int64_t framePosition,
int numFrames) {
int32_t channelCount = output.getSamplesPerFrame();
@@ -35,10 +37,9 @@
inputs[i]->pullData(framePosition, numFrames);
}
-
for (int ch = 0; ch < channelCount; ch++) {
- const float *inputBuffer = inputs[ch]->getFloatBuffer(numFrames);
- float *outputBuffer = output.getFloatBuffer(numFrames) + ch;
+ const float *inputBuffer = inputs[ch]->getBlock();
+ float *outputBuffer = output.getBlock() + ch;
for (int i = 0; i < numFrames; i++) {
// read one, write into the proper interleaved output channel
@@ -47,6 +48,6 @@
outputBuffer += channelCount; // advance to next multichannel frame
}
}
- return AUDIO_RESULT_SUCCESS;
+ return numFrames;
}
diff --git a/apps/OboeTester/app/src/main/cpp/ManyToMultiConverter.h b/apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.h
similarity index 67%
rename from apps/OboeTester/app/src/main/cpp/ManyToMultiConverter.h
rename to apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.h
index 3cdf376..d2f39a3 100644
--- a/apps/OboeTester/app/src/main/cpp/ManyToMultiConverter.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef OBOETESTER_MANY_TO_MULTI_CONVERTER_H
-#define OBOETESTER_MANY_TO_MULTI_CONVERTER_H
+#ifndef FLOWGRAPH_MANY_TO_MULTI_CONVERTER_H
+#define FLOWGRAPH_MANY_TO_MULTI_CONVERTER_H
#include <unistd.h>
#include <sys/types.h>
@@ -24,24 +24,24 @@
#include "AudioProcessorBase.h"
/**
- * Combine multiple mono inputs into one multi-channel output.
+ * Combine multiple mono inputs into one interleaved multi-channel output.
*/
-class ManyToMultiConverter : public AudioProcessorBase {
+class ManyToMultiConverter : public flowgraph::AudioProcessorBase {
public:
explicit ManyToMultiConverter(int32_t channelCount);
virtual ~ManyToMultiConverter() = default;
- AudioResult onProcess(
- uint64_t framePosition,
+ int32_t onProcess(
+ int64_t framePosition,
int numFrames) override;
void setEnabled(bool enabled) {};
- std::vector<std::unique_ptr<AudioInputPort> > inputs;
- AudioOutputPort output;
+ std::vector<std::unique_ptr<flowgraph::AudioFloatInputPort>> inputs;
+ flowgraph::AudioFloatOutputPort output;
private:
};
-#endif //OBOETESTER_MANY_TO_MULTI_CONVERTER_H
+#endif //FLOWGRAPH_MANY_TO_MULTI_CONVERTER_H
diff --git a/apps/OboeTester/app/src/main/cpp/MonoToMultiConverter.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.cpp
similarity index 65%
rename from apps/OboeTester/app/src/main/cpp/MonoToMultiConverter.cpp
rename to apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.cpp
index 53746b4..78aad52 100644
--- a/apps/OboeTester/app/src/main/cpp/MonoToMultiConverter.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.cpp
@@ -14,31 +14,34 @@
* limitations under the License.
*/
+
#include <unistd.h>
#include "AudioProcessorBase.h"
#include "MonoToMultiConverter.h"
+using namespace flowgraph;
+
MonoToMultiConverter::MonoToMultiConverter(int32_t channelCount)
: input(*this, 1)
, output(*this, channelCount) {
}
-AudioResult MonoToMultiConverter::onProcess(
- uint64_t framePosition,
- int numFrames) {
- input.pullData(framePosition, numFrames);
+MonoToMultiConverter::~MonoToMultiConverter() { }
- const float *inputBuffer = input.getFloatBuffer(numFrames);
- float *outputBuffer = output.getFloatBuffer(numFrames);
+int32_t MonoToMultiConverter::onProcess(int64_t framePosition, int32_t numFrames) {
+ int32_t framesToProcess = input.pullData(framePosition, numFrames);
+
+ const float *inputBuffer = input.getBlock();
+ float *outputBuffer = output.getBlock();
int32_t channelCount = output.getSamplesPerFrame();
-
- for (int i = 0; i < numFrames; i++) {
+ // TODO maybe move to audio_util as audio_mono_to_multi()
+ for (int i = 0; i < framesToProcess; i++) {
// read one, write many
float sample = *inputBuffer++;
- for (int ch = 0; ch < channelCount; ch++) {
+ for (int channel = 0; channel < channelCount; channel++) {
*outputBuffer++ = sample;
}
}
- return AUDIO_RESULT_SUCCESS;
+ return framesToProcess;
}
diff --git a/apps/OboeTester/app/src/main/cpp/MonoToMultiConverter.h b/apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.h
similarity index 60%
rename from apps/OboeTester/app/src/main/cpp/MonoToMultiConverter.h
rename to apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.h
index 9132fa1..0a1eb4f 100644
--- a/apps/OboeTester/app/src/main/cpp/MonoToMultiConverter.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.h
@@ -14,33 +14,32 @@
* limitations under the License.
*/
-#ifndef OBOETESTER_MONO_TO_MULTI_CONVERTER_H
-#define OBOETESTER_MONO_TO_MULTI_CONVERTER_H
+#ifndef FLOWGRAPH_MONO_TO_MULTI_CONVERTER_H
+#define FLOWGRAPH_MONO_TO_MULTI_CONVERTER_H
#include <unistd.h>
#include <sys/types.h>
#include "AudioProcessorBase.h"
+namespace flowgraph {
+
/**
- * Duplicate a single mono input across multiple channels of output.
+ * Convert a monophonic stream to a multi-channel stream
+ * with the same signal on each channel.
*/
-class MonoToMultiConverter : AudioProcessorBase {
+class MonoToMultiConverter : public AudioProcessorBase {
public:
explicit MonoToMultiConverter(int32_t channelCount);
- virtual ~MonoToMultiConverter() = default;
+ virtual ~MonoToMultiConverter();
- AudioResult onProcess(
- uint64_t framePosition,
- int numFrames) override;
+ int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
- void setEnabled(bool enabled) {};
-
- AudioInputPort input;
- AudioOutputPort output;
-
-private:
+ AudioFloatInputPort input;
+ AudioFloatOutputPort output;
};
-#endif //OBOETESTER_MONO_TO_MULTI_CONVERTER_H
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_MONO_TO_MULTI_CONVERTER_H
diff --git a/apps/OboeTester/app/src/main/cpp/OscillatorBase.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/OscillatorBase.cpp
similarity index 96%
rename from apps/OboeTester/app/src/main/cpp/OscillatorBase.cpp
rename to apps/OboeTester/app/src/main/cpp/flowgraph/OscillatorBase.cpp
index f839f78..361f4db 100644
--- a/apps/OboeTester/app/src/main/cpp/OscillatorBase.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/OscillatorBase.cpp
@@ -16,6 +16,8 @@
#include "OscillatorBase.h"
+using namespace flowgraph;
+
OscillatorBase::OscillatorBase()
: frequency(*this, 1)
, amplitude(*this, 1)
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/OscillatorBase.h b/apps/OboeTester/app/src/main/cpp/flowgraph/OscillatorBase.h
new file mode 100644
index 0000000..b3144bb
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/OscillatorBase.h
@@ -0,0 +1,86 @@
+/*
+ * 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 NATIVEOBOE_OSCILLATORBASE_H
+#define NATIVEOBOE_OSCILLATORBASE_H
+
+#include "AudioProcessorBase.h"
+
+/**
+ * Base class for various oscillators.
+ * The oscillator has a phase that ranges from -1.0 to +1.0.
+ * That makes it easier to implement simple algebraic waveforms.
+ *
+ * Subclasses must implement onProcess().
+ *
+ * This module has "frequency" and "amplitude" ports for control.
+ */
+
+class OscillatorBase : public flowgraph::AudioProcessorBase {
+public:
+ OscillatorBase();
+
+ virtual ~OscillatorBase() = default;
+
+ void setSampleRate(float sampleRate) {
+ mSampleRate = sampleRate;
+ mFrequencyToPhaseIncrement = 1.0f / sampleRate; // scaler
+ }
+
+ float getSampleRate() {
+ return mSampleRate;
+ }
+
+ /**
+ * Control the frequency of the oscillator in Hz.
+ */
+ flowgraph::AudioFloatInputPort frequency;
+
+ /**
+ * Control the linear amplitude of the oscillator.
+ * Silence is 0.0.
+ * A typical full amplitude would be 1.0.
+ */
+ flowgraph::AudioFloatInputPort amplitude;
+
+ flowgraph::AudioFloatOutputPort output;
+
+protected:
+ /**
+ * Increment phase based on frequency in Hz.
+ * Frequency may be positive or negative.
+ *
+ * Frequency should not exceed +/- Nyquist Rate.
+ * Nyquist Rate is sampleRate/2.
+ */
+ float incrementPhase(float frequency) {
+ mPhase += frequency * mFrequencyToPhaseIncrement;
+ // Wrap phase in the range of -1 to +1
+ if (mPhase >= 1.0f) {
+ mPhase -= 2.0f;
+ } else if (mPhase < -1.0f) {
+ mPhase += 2.0f;
+ }
+ return mPhase;
+ }
+
+ float mPhase = 0.0; // phase that ranges from -1.0 to +1.0
+ float mSampleRate = 0.0f;
+ float mFrequencyToPhaseIncrement = 0.0f; // scaler for converting frequency to phase increment
+};
+
+
+#endif //NATIVEOBOE_OSCILLATORBASE_H
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.cpp
new file mode 100644
index 0000000..acd6fa4
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2015 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 <algorithm>
+#include <unistd.h>
+#include "AudioProcessorBase.h"
+#include "RampLinear.h"
+
+using namespace flowgraph;
+
+RampLinear::RampLinear(int32_t channelCount)
+ : input(*this, channelCount)
+ , output(*this, channelCount) {
+ mTarget.store(1.0f);
+}
+
+void RampLinear::setLengthInFrames(int32_t frames) {
+ mLengthInFrames = frames;
+}
+
+void RampLinear::setTarget(float target) {
+ mTarget.store(target);
+}
+
+float RampLinear::interpolateCurrent() {
+ return mLevelTo - (mRemaining * mScaler);
+}
+
+int32_t RampLinear::onProcess(int64_t framePosition, int32_t numFrames) {
+ int32_t framesToProcess = input.pullData(framePosition, numFrames);
+ const float *inputBuffer = input.getBlock();
+ float *outputBuffer = output.getBlock();
+ int32_t channelCount = output.getSamplesPerFrame();
+
+ float target = getTarget();
+ if (target != mLevelTo) {
+ // Start new ramp. Continue from previous level.
+ mLevelFrom = interpolateCurrent();
+ mLevelTo = target;
+ mRemaining = mLengthInFrames;
+ mScaler = (mLevelTo - mLevelFrom) / mLengthInFrames; // for interpolation
+ }
+
+ int32_t framesLeft = framesToProcess;
+
+ if (mRemaining > 0) { // Ramping? This doesn't happen very often.
+ int32_t framesToRamp = std::min(framesLeft, mRemaining);
+ framesLeft -= framesToRamp;
+ while (framesToRamp > 0) {
+ float currentLevel = interpolateCurrent();
+ for (int ch = 0; ch < channelCount; ch++) {
+ *outputBuffer++ = *inputBuffer++ * currentLevel;
+ }
+ mRemaining--;
+ framesToRamp--;
+ }
+ }
+
+ // Process any frames after the ramp.
+ int32_t samplesLeft = framesLeft * channelCount;
+ for (int i = 0; i < samplesLeft; i++) {
+ *outputBuffer++ = *inputBuffer++ * mLevelTo;
+ }
+
+ return framesToProcess;
+}
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.h b/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.h
new file mode 100644
index 0000000..0d5ed10
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015 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 FLOWGRAPH_RAMP_LINEAR_H
+#define FLOWGRAPH_RAMP_LINEAR_H
+
+#include <atomic>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "AudioProcessorBase.h"
+
+namespace flowgraph {
+
+/**
+ * When the target is modified then the output will ramp smoothly
+ * between the original and the new target value.
+ * This can be used to smooth out control values and reduce pops.
+ *
+ * The target may be updated while a ramp is in progress, which will trigger
+ * a new ramp from the current value.
+ */
+class RampLinear : public AudioProcessorBase {
+public:
+ explicit RampLinear(int32_t channelCount);
+
+ virtual ~RampLinear() = default;
+
+ int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+
+ /**
+ * This is used for the next ramp.
+ * Calling this does not affect a ramp that is in progress.
+ */
+ void setLengthInFrames(int32_t frames);
+
+ int32_t getLengthInFrames() const {
+ return mLengthInFrames;
+ }
+
+ /**
+ * This may be safely called by another thread.
+ * @param target
+ */
+ void setTarget(float target);
+
+ float getTarget() const {
+ return mTarget.load();
+ }
+
+ /**
+ * Force the nextSegment to start from this level.
+ *
+ * WARNING: this can cause a discontinuity if called while the ramp is being used.
+ * Only call this when setting the initial ramp.
+ *
+ * @param level
+ */
+ void forceCurrent(float level) {
+ mLevelFrom = level;
+ mLevelTo = level;
+ }
+
+ AudioFloatInputPort input;
+ AudioFloatOutputPort output;
+
+private:
+
+ float interpolateCurrent();
+
+ std::atomic<float> mTarget;
+
+ int32_t mLengthInFrames = 48000.0f / 100.0f ; // 10 msec at 48000 Hz;
+ int32_t mRemaining = 0;
+ float mScaler = 0.0f;
+ float mLevelFrom = 0.0f;
+ float mLevelTo = 0.0f;
+};
+
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_RAMP_LINEAR_H
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.cpp
new file mode 100644
index 0000000..149e489
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2015 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 <math.h>
+#include <unistd.h>
+
+#include "SawtoothOscillator.h"
+
+SawtoothOscillator::SawtoothOscillator()
+ : OscillatorBase() {
+}
+
+int32_t SawtoothOscillator::onProcess(
+ int64_t framePosition,
+ int numFrames) {
+
+ frequency.pullData(framePosition, numFrames);
+ amplitude.pullData(framePosition, numFrames);
+
+ const float *frequencies = frequency.getBlock();
+ const float *amplitudes = amplitude.getBlock();
+ float *buffer = output.getBlock();
+
+ // Use the phase directly as a non-band-limited "sawtooth".
+ // This will generate unpleasant aliasing artifacts at higher frequencies.
+ for (int i = 0; i < numFrames; i++) {
+ float phase = incrementPhase(frequencies[i]); // phase ranges from -1 to +1
+ *buffer++ = phase * amplitudes[i];
+ }
+
+ return numFrames;
+}
diff --git a/apps/OboeTester/app/src/main/cpp/SineGenerator.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.h
similarity index 61%
copy from apps/OboeTester/app/src/main/cpp/SineGenerator.h
copy to apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.h
index ca0f988..6d444ae 100644
--- a/apps/OboeTester/app/src/main/cpp/SineGenerator.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.h
@@ -14,21 +14,25 @@
* limitations under the License.
*/
-#ifndef NATIVEOBOE_SINEGENERATOR_H
-#define NATIVEOBOE_SINEGENERATOR_H
+#ifndef FLOWGRAPH_SAWTOOTH_OSCILLATOR_H
+#define FLOWGRAPH_SAWTOOTH_OSCILLATOR_H
#include <unistd.h>
#include "OscillatorBase.h"
-class SineGenerator : public OscillatorBase {
+/**
+ * Oscillator that generates a sawtooth wave at the specified frequency and amplitude.
+ *
+ * The waveform is not band-limited so it will have aliasing artifacts at higher frequencies.
+ */
+class SawtoothOscillator : public OscillatorBase {
public:
- SineGenerator();
+ SawtoothOscillator();
- AudioResult onProcess(
- uint64_t framePosition,
+ int32_t onProcess(
+ int64_t framePosition,
int numFrames) override;
};
-
-#endif //NATIVEOBOE_SINEGENERATOR_H
+#endif //FLOWGRAPH_SAWTOOTH_OSCILLATOR_H
diff --git a/apps/OboeTester/app/src/main/cpp/SineGenerator.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.cpp
similarity index 61%
rename from apps/OboeTester/app/src/main/cpp/SineGenerator.cpp
rename to apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.cpp
index 58c55c5..7657b0c 100644
--- a/apps/OboeTester/app/src/main/cpp/SineGenerator.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.cpp
@@ -17,28 +17,32 @@
#include <math.h>
#include <unistd.h>
-#include "SineGenerator.h"
+#include "SineOscillator.h"
-SineGenerator::SineGenerator()
+/*
+ * This calls sinf() so it is not very efficient.
+ * A more efficient implementation might use a wave-table or a polynomial.
+ */
+SineOscillator::SineOscillator()
: OscillatorBase() {
}
-AudioResult SineGenerator::onProcess(
- uint64_t framePosition,
+int32_t SineOscillator::onProcess(
+ int64_t framePosition,
int numFrames) {
frequency.pullData(framePosition, numFrames);
amplitude.pullData(framePosition, numFrames);
- const float *frequencies = frequency.getFloatBuffer(numFrames);
- const float *amplitudes = amplitude.getFloatBuffer(numFrames);
- float *buffer = output.getFloatBuffer(numFrames);
+ const float *frequencies = frequency.getBlock();
+ const float *amplitudes = amplitude.getBlock();
+ float *buffer = output.getBlock();
// Generate sine wave.
for (int i = 0; i < numFrames; i++) {
- float phase = incrementPhase(frequencies[i]);
- *buffer++ = sinf(phase) * amplitudes[i];
+ float phase = incrementPhase(frequencies[i]); // phase ranges from -1 to +1
+ *buffer++ = sinf(phase * M_PI) * amplitudes[i];
}
- return AUDIO_RESULT_SUCCESS;
+ return numFrames;
}
diff --git a/apps/OboeTester/app/src/main/cpp/SineGenerator.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.h
similarity index 68%
rename from apps/OboeTester/app/src/main/cpp/SineGenerator.h
rename to apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.h
index ca0f988..a7ab8a7 100644
--- a/apps/OboeTester/app/src/main/cpp/SineGenerator.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.h
@@ -14,21 +14,23 @@
* limitations under the License.
*/
-#ifndef NATIVEOBOE_SINEGENERATOR_H
-#define NATIVEOBOE_SINEGENERATOR_H
+#ifndef FLOWGRAPH_SINE_OSCILLATOR_H
+#define FLOWGRAPH_SINE_OSCILLATOR_H
#include <unistd.h>
#include "OscillatorBase.h"
-class SineGenerator : public OscillatorBase {
+/**
+ * Oscillator that generates a sine wave at the specified frequency and amplitude.
+ */
+class SineOscillator : public OscillatorBase {
public:
- SineGenerator();
+ SineOscillator();
- AudioResult onProcess(
- uint64_t framePosition,
+ int32_t onProcess(
+ int64_t framePosition,
int numFrames) override;
};
-
-#endif //NATIVEOBOE_SINEGENERATOR_H
+#endif //FLOWGRAPH_SINE_OSCILLATOR_H
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.cpp
new file mode 100644
index 0000000..fb3dcbc
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 <algorithm>
+#include <unistd.h>
+#include "AudioProcessorBase.h"
+#include "SinkFloat.h"
+
+using namespace flowgraph;
+
+SinkFloat::SinkFloat(int32_t channelCount)
+ : AudioSink(channelCount) {
+}
+
+int32_t SinkFloat::read(void *data, int32_t numFrames) {
+ float *floatData = (float *) data;
+ int32_t channelCount = input.getSamplesPerFrame();
+
+ int32_t framesLeft = numFrames;
+ while (framesLeft > 0) {
+ // Run the graph and pull data through the input port.
+ int32_t framesRead = pull(framesLeft);
+ if (framesRead <= 0) {
+ break;
+ }
+ const float *signal = input.getBlock();
+ int32_t numSamples = framesRead * channelCount;
+ memcpy(floatData, signal, numSamples * sizeof(float));
+ floatData += numSamples;
+ framesLeft -= framesRead;
+ }
+ return numFrames - framesLeft;
+}
diff --git a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.h
similarity index 66%
copy from apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
copy to apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.h
index 5db11b5..be3fc88 100644
--- a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.h
@@ -14,25 +14,28 @@
* limitations under the License.
*/
-#ifndef NATIVEOBOE_IMPULSE_GENERATOR_H
-#define NATIVEOBOE_IMPULSE_GENERATOR_H
+
+#ifndef FLOWGRAPH_SINK_FLOAT_H
+#define FLOWGRAPH_SINK_FLOAT_H
#include <unistd.h>
#include <sys/types.h>
#include "AudioProcessorBase.h"
-#include "OscillatorBase.h"
-class ImpulseGenerator : public OscillatorBase {
+namespace flowgraph {
+
+/**
+ * AudioSink that lets you read data as 32-bit floats.
+ */
+class SinkFloat : public AudioSink {
public:
- ImpulseGenerator();
+ explicit SinkFloat(int32_t channelCount);
- AudioResult onProcess(
- uint64_t framePosition,
- int numFrames);
-
-
+ int32_t read(void *data, int32_t numFrames) override;
};
-#endif //NATIVEOBOE_IMPULSE_GENERATOR_H
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SINK_FLOAT_H
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.cpp
new file mode 100644
index 0000000..1e66cbd
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.cpp
@@ -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.
+ */
+
+#include <algorithm>
+#include <unistd.h>
+
+#include "SinkI16.h"
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+#include <audio_utils/primitives.h>
+#endif
+
+using namespace flowgraph;
+
+SinkI16::SinkI16(int32_t channelCount)
+ : AudioSink(channelCount) {}
+
+int32_t SinkI16::read(void *data, int32_t numFrames) {
+ int16_t *shortData = (int16_t *) data;
+ const int32_t channelCount = input.getSamplesPerFrame();
+
+ int32_t framesLeft = numFrames;
+ while (framesLeft > 0) {
+ // Run the graph and pull data through the input port.
+ int32_t framesRead = pull(framesLeft);
+ if (framesRead <= 0) {
+ break;
+ }
+ const float *signal = input.getBlock();
+ int32_t numSamples = framesRead * channelCount;
+#if FLOWGRAPH_ANDROID_INTERNAL
+ memcpy_to_i16_from_float(shortData, signal, numSamples);
+ shortData += numSamples;
+ signal += numSamples;
+#else
+ for (int i = 0; i < numSamples; i++) {
+ int32_t n = (int32_t) (*signal++ * 32768.0f);
+ *shortData++ = std::min(INT16_MAX, std::max(INT16_MIN, n)); // clip
+ }
+#endif
+ framesLeft -= framesRead;
+ }
+ return numFrames - framesLeft;
+}
diff --git a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.h
similarity index 66%
copy from apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
copy to apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.h
index 5db11b5..f861544 100644
--- a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.h
@@ -14,25 +14,26 @@
* limitations under the License.
*/
-#ifndef NATIVEOBOE_IMPULSE_GENERATOR_H
-#define NATIVEOBOE_IMPULSE_GENERATOR_H
+#ifndef FLOWGRAPH_SINK_I16_H
+#define FLOWGRAPH_SINK_I16_H
#include <unistd.h>
#include <sys/types.h>
#include "AudioProcessorBase.h"
-#include "OscillatorBase.h"
-class ImpulseGenerator : public OscillatorBase {
+namespace flowgraph {
+
+/**
+ * AudioSink that lets you read data as 16-bit signed integers.
+ */
+class SinkI16 : public AudioSink {
public:
- ImpulseGenerator();
+ explicit SinkI16(int32_t channelCount);
- AudioResult onProcess(
- uint64_t framePosition,
- int numFrames);
-
-
-
+ int32_t read(void *data, int32_t numFrames) override;
};
-#endif //NATIVEOBOE_IMPULSE_GENERATOR_H
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SINK_I16_H
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.cpp
new file mode 100644
index 0000000..fa8c68d
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 <algorithm>
+#include <unistd.h>
+
+
+#include "AudioProcessorBase.h"
+#include "SinkI24.h"
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+#include <audio_utils/primitives.h>
+#endif
+
+using namespace flowgraph;
+
+SinkI24::SinkI24(int32_t channelCount)
+ : AudioSink(channelCount) {}
+
+int32_t SinkI24::read(void *data, int32_t numFrames) {
+ uint8_t *byteData = (uint8_t *) data;
+ const int32_t channelCount = input.getSamplesPerFrame();
+
+ int32_t framesLeft = numFrames;
+ while (framesLeft > 0) {
+ // Run the graph and pull data through the input port.
+ int32_t framesRead = pull(framesLeft);
+ if (framesRead <= 0) {
+ break;
+ }
+ const float *floatData = input.getBlock();
+ int32_t numSamples = framesRead * channelCount;
+#if FLOWGRAPH_ANDROID_INTERNAL
+ memcpy_to_p24_from_float(byteData, floatData, numSamples);
+ static const int kBytesPerI24Packed = 3;
+ byteData += numSamples * kBytesPerI24Packed;
+ floatData += numSamples;
+#else
+ const int32_t kI24PackedMax = 0x007FFFFF;
+ const int32_t kI24PackedMin = 0xFF800000;
+ for (int i = 0; i < numSamples; i++) {
+ int32_t n = (int32_t) (*floatData++ * 0x00800000);
+ n = std::min(kI24PackedMax, std::max(kI24PackedMin, n)); // clip
+ // Write as a packed 24-bit integer in Little Endian format.
+ *byteData++ = (uint8_t) n;
+ *byteData++ = (uint8_t) (n >> 8);
+ *byteData++ = (uint8_t) (n >> 16);
+ }
+#endif
+ framesLeft -= framesRead;
+ }
+ return numFrames - framesLeft;
+}
diff --git a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.h
similarity index 64%
copy from apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
copy to apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.h
index 5db11b5..682b16f 100644
--- a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.h
@@ -14,25 +14,27 @@
* limitations under the License.
*/
-#ifndef NATIVEOBOE_IMPULSE_GENERATOR_H
-#define NATIVEOBOE_IMPULSE_GENERATOR_H
+#ifndef FLOWGRAPH_SINK_I24_H
+#define FLOWGRAPH_SINK_I24_H
#include <unistd.h>
#include <sys/types.h>
#include "AudioProcessorBase.h"
-#include "OscillatorBase.h"
-class ImpulseGenerator : public OscillatorBase {
+namespace flowgraph {
+
+/**
+ * AudioSink that lets you read data as packed 24-bit signed integers.
+ * The sample size is 3 bytes.
+ */
+class SinkI24 : public AudioSink {
public:
- ImpulseGenerator();
+ explicit SinkI24(int32_t channelCount);
- AudioResult onProcess(
- uint64_t framePosition,
- int numFrames);
-
-
-
+ int32_t read(void *data, int32_t numFrames) override;
};
-#endif //NATIVEOBOE_IMPULSE_GENERATOR_H
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SINK_I24_H
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.cpp
new file mode 100644
index 0000000..4bb674f
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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 <algorithm>
+#include <unistd.h>
+#include "AudioProcessorBase.h"
+#include "SourceFloat.h"
+
+using namespace flowgraph;
+
+SourceFloat::SourceFloat(int32_t channelCount)
+ : AudioSource(channelCount) {
+}
+
+int32_t SourceFloat::onProcess(int64_t framePosition, int32_t numFrames) {
+
+ float *outputBuffer = output.getBlock();
+ int32_t channelCount = output.getSamplesPerFrame();
+
+ int32_t framesLeft = mSizeInFrames - mFrameIndex;
+ int32_t framesToProcess = std::min(numFrames, framesLeft);
+ int32_t numSamples = framesToProcess * channelCount;
+
+ const float *floatBase = (float *) mData;
+ const float *floatData = &floatBase[mFrameIndex * channelCount];
+ memcpy(outputBuffer, floatData, numSamples * sizeof(float));
+ mFrameIndex += framesToProcess;
+ return framesToProcess;
+}
+
diff --git a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.h
similarity index 64%
copy from apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
copy to apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.h
index 5db11b5..efede25 100644
--- a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.h
@@ -14,25 +14,26 @@
* limitations under the License.
*/
-#ifndef NATIVEOBOE_IMPULSE_GENERATOR_H
-#define NATIVEOBOE_IMPULSE_GENERATOR_H
+#ifndef FLOWGRAPH_SOURCE_FLOAT_H
+#define FLOWGRAPH_SOURCE_FLOAT_H
#include <unistd.h>
#include <sys/types.h>
#include "AudioProcessorBase.h"
-#include "OscillatorBase.h"
-class ImpulseGenerator : public OscillatorBase {
+namespace flowgraph {
+
+/**
+ * AudioSource that reads a block of pre-defined float data.
+ */
+class SourceFloat : public AudioSource {
public:
- ImpulseGenerator();
+ explicit SourceFloat(int32_t channelCount);
- AudioResult onProcess(
- uint64_t framePosition,
- int numFrames);
-
-
-
+ int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
};
-#endif //NATIVEOBOE_IMPULSE_GENERATOR_H
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SOURCE_FLOAT_H
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.cpp
new file mode 100644
index 0000000..f172968
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 <algorithm>
+#include <unistd.h>
+
+#include "AudioProcessorBase.h"
+#include "SourceI16.h"
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+#include <audio_utils/primitives.h>
+#endif
+
+using namespace flowgraph;
+
+SourceI16::SourceI16(int32_t channelCount)
+ : AudioSource(channelCount) {
+}
+
+int32_t SourceI16::onProcess(int64_t framePosition, int32_t numFrames) {
+ float *floatData = output.getBlock();
+ int32_t channelCount = output.getSamplesPerFrame();
+
+ int32_t framesLeft = mSizeInFrames - mFrameIndex;
+ int32_t framesToProcess = std::min(numFrames, framesLeft);
+ int32_t numSamples = framesToProcess * channelCount;
+
+ const int16_t *shortBase = static_cast<const int16_t *>(mData);
+ const int16_t *shortData = &shortBase[mFrameIndex * channelCount];
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+ memcpy_to_float_from_i16(floatData, shortData, numSamples);
+#else
+ for (int i = 0; i < numSamples; i++) {
+ *floatData++ = *shortData++ * (1.0f / 32768);
+ }
+#endif
+
+ mFrameIndex += framesToProcess;
+ return framesToProcess;
+}
\ No newline at end of file
diff --git a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.h
similarity index 64%
copy from apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
copy to apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.h
index 5db11b5..9481e0b 100644
--- a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.h
@@ -14,25 +14,25 @@
* limitations under the License.
*/
-#ifndef NATIVEOBOE_IMPULSE_GENERATOR_H
-#define NATIVEOBOE_IMPULSE_GENERATOR_H
+#ifndef FLOWGRAPH_SOURCE_I16_H
+#define FLOWGRAPH_SOURCE_I16_H
#include <unistd.h>
#include <sys/types.h>
#include "AudioProcessorBase.h"
-#include "OscillatorBase.h"
-class ImpulseGenerator : public OscillatorBase {
+namespace flowgraph {
+/**
+ * AudioSource that reads a block of pre-defined 16-bit integer data.
+ */
+class SourceI16 : public AudioSource {
public:
- ImpulseGenerator();
+ explicit SourceI16(int32_t channelCount);
- AudioResult onProcess(
- uint64_t framePosition,
- int numFrames);
-
-
-
+ int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
};
-#endif //NATIVEOBOE_IMPULSE_GENERATOR_H
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SOURCE_I16_H
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.cpp
new file mode 100644
index 0000000..fee1ce4
--- /dev/null
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.cpp
@@ -0,0 +1,65 @@
+/*
+ * 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 <algorithm>
+#include <unistd.h>
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+#include <audio_utils/primitives.h>
+#endif
+
+#include "AudioProcessorBase.h"
+#include "SourceI24.h"
+
+using namespace flowgraph;
+
+constexpr int kBytesPerI24Packed = 3;
+
+SourceI24::SourceI24(int32_t channelCount)
+ : AudioSource(channelCount) {
+}
+
+int32_t SourceI24::onProcess(int64_t framePosition, int32_t numFrames) {
+ float *floatData = output.getBlock();
+ int32_t channelCount = output.getSamplesPerFrame();
+
+ int32_t framesLeft = mSizeInFrames - mFrameIndex;
+ int32_t framesToProcess = std::min(numFrames, framesLeft);
+ int32_t numSamples = framesToProcess * channelCount;
+
+ const uint8_t *byteBase = (uint8_t *) mData;
+ const uint8_t *byteData = &byteBase[mFrameIndex * channelCount * kBytesPerI24Packed];
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+ memcpy_to_float_from_p24(floatData, byteData, numSamples);
+#else
+ static const float scale = 1. / (float)(1UL << 31);
+ for (int i = 0; i < numSamples; i++) {
+ // Assemble the data assuming Little Endian format.
+ int32_t pad = byteData[2];
+ pad <<= 8;
+ pad |= byteData[1];
+ pad <<= 8;
+ pad |= byteData[0];
+ pad <<= 8; // Shift to 32 bit data so the sign is correct.
+ byteData += kBytesPerI24Packed;
+ *floatData++ = pad * scale; // scale to range -1.0 to 1.0
+ }
+#endif
+
+ mFrameIndex += framesToProcess;
+ return framesToProcess;
+}
\ No newline at end of file
diff --git a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.h
similarity index 64%
copy from apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
copy to apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.h
index 5db11b5..c76b82d 100644
--- a/apps/OboeTester/app/src/main/cpp/ImpulseGenerator.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.h
@@ -14,25 +14,26 @@
* limitations under the License.
*/
-#ifndef NATIVEOBOE_IMPULSE_GENERATOR_H
-#define NATIVEOBOE_IMPULSE_GENERATOR_H
+#ifndef FLOWGRAPH_SOURCE_I24_H
+#define FLOWGRAPH_SOURCE_I24_H
#include <unistd.h>
#include <sys/types.h>
#include "AudioProcessorBase.h"
-#include "OscillatorBase.h"
-class ImpulseGenerator : public OscillatorBase {
+namespace flowgraph {
+
+/**
+ * AudioSource that reads a block of pre-defined 24-bit packed integer data.
+ */
+class SourceI24 : public AudioSource {
public:
- ImpulseGenerator();
+ explicit SourceI24(int32_t channelCount);
- AudioResult onProcess(
- uint64_t framePosition,
- int numFrames);
-
-
-
+ int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
};
-#endif //NATIVEOBOE_IMPULSE_GENERATOR_H
+} /* namespace flowgraph */
+
+#endif //FLOWGRAPH_SOURCE_I24_H
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioOutputTester.java b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioOutputTester.java
index 2d49ae8..936aff2 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioOutputTester.java
+++ b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/AudioOutputTester.java
@@ -36,7 +36,7 @@
Log.i(TapToToneActivity.TAG, "create OboeAudioOutputStream ---------");
mOboeAudioOutputStream = new OboeAudioOutputStream();
mCurrentAudioStream = mOboeAudioOutputStream;
- setToneType(OboeAudioOutputStream.TONE_TYPE_SINE_STEADY);
+ setToneType(OboeAudioOutputStream.TONE_TYPE_SINE);
setEnabled(false);
}
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/OboeAudioOutputStream.java b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/OboeAudioOutputStream.java
index 763e4c3..da33822 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/OboeAudioOutputStream.java
+++ b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/OboeAudioOutputStream.java
@@ -23,8 +23,9 @@
// WARNING - must match order in strings.xml
public static final int TONE_TYPE_SAW_PING = 0;
- public static final int TONE_TYPE_SINE_STEADY = 1;
+ public static final int TONE_TYPE_SINE = 1;
public static final int TONE_TYPE_IMPULSE = 2;
+ public static final int TONE_TYPE_SAWTOOTH = 3;
@Override
public boolean isInput() {
diff --git a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestOutputActivity.java b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestOutputActivity.java
index f0e5f64..342a429 100644
--- a/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestOutputActivity.java
+++ b/apps/OboeTester/app/src/main/java/com/google/sample/oboe/manualtest/TestOutputActivity.java
@@ -20,8 +20,6 @@
import android.view.View;
import android.widget.CheckBox;
-import com.google.sample.oboe.manualtest.R;
-
/**
* Base class for output test activities
*/
@@ -68,7 +66,7 @@
public void startAudio() {
super.startAudio();
- mAudioOutTester.setToneType(OboeAudioOutputStream.TONE_TYPE_SINE_STEADY);
+ mAudioOutTester.setToneType(OboeAudioOutputStream.TONE_TYPE_SINE);
mAudioOutTester.setEnabled(true);
}