aboutsummaryrefslogtreecommitdiff
path: root/samples
diff options
context:
space:
mode:
authorPaul McLean <pmclean@google.com>2020-08-26 13:50:47 -0600
committerPaul McLean <pmclean@google.com>2020-08-31 12:52:16 -0600
commit19143c3f07a074e660113df879862d0826b2a5b2 (patch)
treeae42934a847307f005ca7c188c9cc9e01adc5264 /samples
parentc5dcad3bbb341aa447728f931141e8b0f5dba7d9 (diff)
downloadoboe-19143c3f07a074e660113df879862d0826b2a5b2.tar.gz
Added resample on sample load to avoid the resampling penalty at play
time.
Diffstat (limited to 'samples')
-rw-r--r--samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp12
-rw-r--r--samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumPlayer.kt12
-rw-r--r--samples/iolib/src/main/cpp/CMakeLists.txt1
-rw-r--r--samples/iolib/src/main/cpp/player/SampleBuffer.cpp74
-rw-r--r--samples/iolib/src/main/cpp/player/SampleBuffer.h2
-rw-r--r--samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp29
-rw-r--r--samples/iolib/src/main/cpp/player/SimpleMultiPlayer.h4
7 files changed, 117 insertions, 17 deletions
diff --git a/samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp b/samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp
index 5ae41f73..9f55e137 100644
--- a/samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp
+++ b/samples/drumthumper/src/main/cpp/DrumPlayerJNI.cpp
@@ -45,11 +45,11 @@ static SimpleMultiPlayer sDTPlayer;
* Native (JNI) implementation of DrumPlayer.setupAudioStreamNative()
*/
JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_setupAudioStreamNative(
- JNIEnv* env, jobject, jint sampleRate, jint numChannels) {
+ JNIEnv* env, jobject, jint numChannels) {
__android_log_print(ANDROID_LOG_INFO, TAG, "%s", "init()");
// we know in this case that the sample buffers are all 1-channel, 41K
- sDTPlayer.setupAudioStream(sampleRate, numChannels);
+ sDTPlayer.setupAudioStream(numChannels);
}
/**
@@ -69,7 +69,7 @@ JNIEXPORT void JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_teardow
* Native (JNI) implementation of DrumPlayer.loadWavAssetNative()
*/
JNIEXPORT jboolean JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_loadWavAssetNative(
- JNIEnv* env, jobject, jbyteArray bytearray, jint index, jfloat pan, jint rate, jint channels) {
+ JNIEnv* env, jobject, jbyteArray bytearray, jint index, jfloat pan, jint channels) {
int len = env->GetArrayLength (bytearray);
unsigned char* buf = new unsigned char[len];
@@ -80,12 +80,14 @@ JNIEXPORT jboolean JNICALL Java_com_plausiblesoftware_drumthumper_DrumPlayer_loa
WavStreamReader reader(&stream);
reader.parse();
- jboolean isFormatValid =
- (reader.getSampleRate() == rate) && (reader.getNumChannels() == channels);
+ jboolean isFormatValid = reader.getNumChannels() == channels;
SampleBuffer* sampleBuffer = new SampleBuffer();
sampleBuffer->loadSampleData(&reader);
+ int sampleRate = sDTPlayer.getDeviceSampleRate(2 /*channelCount*/);
+ sampleBuffer->resampleData(sampleRate);
+
OneShotSampleSource* source = new OneShotSampleSource(sampleBuffer, pan);
sDTPlayer.addSampleSource(source, sampleBuffer);
diff --git a/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumPlayer.kt b/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumPlayer.kt
index 8d50510a..fbe75539 100644
--- a/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumPlayer.kt
+++ b/samples/drumthumper/src/main/java/com/plausibleaudio/drumthumper/DrumPlayer.kt
@@ -27,8 +27,8 @@ class DrumPlayer {
// This IS NOT the channel format of the source samples
// (which must be mono).
val NUM_SAMPLE_CHANNELS: Int = 1; // All WAV resource must be mono
- val SAMPLE_RATE: Int = 44100 // All the input samples are assumed to BE 44.1K
- // All the input samples are assumed to be mono.
+// val SAMPLE_RATE: Int = 44100 // All the input samples are assumed to BE 44.1K
+// // All the input samples are assumed to be mono.
// Sample Buffer IDs
val BASSDRUM: Int = 0
@@ -55,7 +55,7 @@ class DrumPlayer {
}
fun setupAudioStream() {
- setupAudioStreamNative(SAMPLE_RATE, NUM_PLAY_CHANNELS)
+ setupAudioStreamNative(NUM_PLAY_CHANNELS)
}
fun teardownAudioStream() {
@@ -89,7 +89,7 @@ class DrumPlayer {
var dataLen = assetFD.getLength().toInt()
var dataBytes: ByteArray = ByteArray(dataLen)
dataStream.read(dataBytes, 0, dataLen)
- returnVal = loadWavAssetNative(dataBytes, index, pan, SAMPLE_RATE, NUM_SAMPLE_CHANNELS)
+ returnVal = loadWavAssetNative(dataBytes, index, pan, NUM_SAMPLE_CHANNELS)
assetFD.close()
} catch (ex: IOException) {
Log.i(TAG, "IOException" + ex)
@@ -98,11 +98,11 @@ class DrumPlayer {
return returnVal
}
- external fun setupAudioStreamNative(sampleRate: Int, numChannels: Int)
+ external fun setupAudioStreamNative(numChannels: Int)
external fun teardownAudioStreamNative()
external fun loadWavAssetNative(
- wavBytes: ByteArray, index: Int, pan: Float, rate: Int, channels: Int) : Boolean
+ wavBytes: ByteArray, index: Int, pan: Float, channels: Int) : Boolean
external fun unloadWavAssetsNative()
external fun trigger(drumIndex: Int)
diff --git a/samples/iolib/src/main/cpp/CMakeLists.txt b/samples/iolib/src/main/cpp/CMakeLists.txt
index 2c3d9232..dd8c6263 100644
--- a/samples/iolib/src/main/cpp/CMakeLists.txt
+++ b/samples/iolib/src/main/cpp/CMakeLists.txt
@@ -29,6 +29,7 @@ set (PARSELIB_DIR ../../../../parselib)
include_directories(
${PARSELIB_DIR}/src/main/cpp
${OBOE_DIR}/include
+ ${OBOE_DIR}/src/flowgraph
${CMAKE_CURRENT_LIST_DIR}
../../../../shared)
diff --git a/samples/iolib/src/main/cpp/player/SampleBuffer.cpp b/samples/iolib/src/main/cpp/player/SampleBuffer.cpp
index ca3a9058..a1544bd9 100644
--- a/samples/iolib/src/main/cpp/player/SampleBuffer.cpp
+++ b/samples/iolib/src/main/cpp/player/SampleBuffer.cpp
@@ -16,8 +16,13 @@
#include "SampleBuffer.h"
+// Resampler Includes
+#include <resampler/MultiChannelResampler.h>
+
#include "wav/WavStreamReader.h"
+using namespace resampler;
+
namespace iolib {
void SampleBuffer::loadSampleData(parselib::WavStreamReader* reader) {
@@ -41,4 +46,73 @@ void SampleBuffer::unloadSampleData() {
mNumSamples = 0;
}
+class ResampleBlock {
+public:
+ int32_t mSampleRate;
+ float* mBuffer;
+ int32_t mNumFrames;
+};
+
+void resampleData(const ResampleBlock& input, ResampleBlock* output) {
+ // Calculate output buffer size
+ double temp =
+ ((double)input.mNumFrames * (double)output->mSampleRate) / (double)input.mSampleRate;
+
+ // round up
+ int32_t numOutFrames = (int32_t)(temp + 0.5);
+ output->mNumFrames = numOutFrames;
+
+ MultiChannelResampler *resampler = MultiChannelResampler::make(
+ 1, // channel count
+ input.mSampleRate, // input sampleRate
+ output->mSampleRate, // output sampleRate
+ MultiChannelResampler::Quality::Medium); // conversion quality
+
+ float *inputBuffer = input.mBuffer;; // multi-channel buffer to be consumed
+ float *outputBuffer = new float[numOutFrames]; // multi-channel buffer to be filled
+ output->mBuffer = outputBuffer;
+ int numInputFrames = input.mNumFrames; // number of frames of input
+ int numOutputFrames = 0;
+ int channelCount = 1; // 1 for mono, 2 for stereo
+
+ int inputFramesLeft = numInputFrames;
+ while (inputFramesLeft > 0) {
+ if(resampler->isWriteNeeded()) {
+ resampler->writeNextFrame(inputBuffer);
+ inputBuffer += channelCount;
+ inputFramesLeft--;
+ } else {
+ resampler->readNextFrame(outputBuffer);
+ outputBuffer += channelCount;
+ numOutputFrames++;
+ }
+ }
+
+ delete resampler;
}
+
+void SampleBuffer::resampleData(int sampleRate) {
+ if (mAudioProperties.sampleRate == sampleRate) {
+ // nothing to do
+ return;
+ }
+
+ ResampleBlock inputBlock;
+ inputBlock.mBuffer = mSampleData;
+ inputBlock.mNumFrames = mNumSamples;
+ inputBlock.mSampleRate = mAudioProperties.sampleRate;
+
+ ResampleBlock outputBlock;
+ outputBlock.mSampleRate = sampleRate;
+ iolib::resampleData(inputBlock, &outputBlock);
+
+ // delete previous samples
+ delete[] mSampleData;
+
+ // install the resampled data
+ mSampleData = outputBlock.mBuffer;
+ mNumSamples = outputBlock.mNumFrames;
+ mAudioProperties.sampleRate = outputBlock.mSampleRate;
+}
+
+} // namespace iolib
diff --git a/samples/iolib/src/main/cpp/player/SampleBuffer.h b/samples/iolib/src/main/cpp/player/SampleBuffer.h
index 9d61f28d..c92ee78f 100644
--- a/samples/iolib/src/main/cpp/player/SampleBuffer.h
+++ b/samples/iolib/src/main/cpp/player/SampleBuffer.h
@@ -38,6 +38,8 @@ public:
void loadSampleData(parselib::WavStreamReader* reader);
void unloadSampleData();
+ void resampleData(int sampleRate);
+
virtual AudioProperties getProperties() const { return mAudioProperties; }
float* getSampleData() { return mSampleData; }
diff --git a/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp b/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp
index 6110b290..3c24b9e0 100644
--- a/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp
+++ b/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp
@@ -34,7 +34,7 @@ namespace iolib {
constexpr int32_t kBufferSizeInBursts = 2; // Use 2 bursts as the buffer size (double buffer)
SimpleMultiPlayer::SimpleMultiPlayer()
- : mChannelCount(0), mSampleRate(0), mOutputReset(false)
+ : mChannelCount(0), mOutputReset(false)
{}
DataCallbackResult SimpleMultiPlayer::onAudioReady(AudioStream *oboeStream, void *audioData,
@@ -72,13 +72,34 @@ void SimpleMultiPlayer::onErrorBeforeClose(AudioStream *, Result error) {
__android_log_print(ANDROID_LOG_INFO, TAG, "==== onErrorBeforeClose() error:%d", error);
}
+int SimpleMultiPlayer::getDeviceSampleRate(int32_t channelCount) {
+
+ // Create an audio stream
+ AudioStreamBuilder builder;
+ builder.setChannelCount(channelCount);
+ builder.setPerformanceMode(PerformanceMode::LowLatency);
+ builder.setSharingMode(SharingMode::Exclusive);
+ builder.setSampleRateConversionQuality(SampleRateConversionQuality::Medium);
+
+ oboe::ManagedStream audioStream;
+ Result result = builder.openManagedStream(audioStream);
+ if (result != Result::OK) {
+ __android_log_print(ANDROID_LOG_ERROR, TAG,
+ "openStream failed. Error: %s", convertToText(result));
+ return 0;
+ } else {
+ int rate = audioStream->getSampleRate();
+ return rate;
+ }
+}
+
bool SimpleMultiPlayer::openStream() {
__android_log_print(ANDROID_LOG_INFO, TAG, "openStream()");
// Create an audio stream
AudioStreamBuilder builder;
builder.setChannelCount(mChannelCount);
- builder.setSampleRate(mSampleRate);
+ // builder.setSampleRate(mSampleRate); // we will resample to device rate
builder.setCallback(this);
builder.setPerformanceMode(PerformanceMode::LowLatency);
builder.setSharingMode(SharingMode::Exclusive);
@@ -117,11 +138,9 @@ bool SimpleMultiPlayer::openStream() {
return true;
}
-void SimpleMultiPlayer::setupAudioStream(int32_t sampleRate, int32_t channelCount) {
+void SimpleMultiPlayer::setupAudioStream(int32_t channelCount) {
__android_log_print(ANDROID_LOG_INFO, TAG, "setupAudioStream()");
mChannelCount = channelCount;
- mSampleRate = sampleRate;
- mSampleRate = sampleRate;
openStream();
}
diff --git a/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.h b/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.h
index 3e0a1c77..efec8b91 100644
--- a/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.h
+++ b/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.h
@@ -41,9 +41,11 @@ public:
virtual void onErrorAfterClose(oboe::AudioStream *oboeStream, oboe::Result error) override;
virtual void onErrorBeforeClose(oboe::AudioStream * oboeStream, oboe::Result error) override;
- void setupAudioStream(int32_t sampleRate, int32_t channelCount);
+ void setupAudioStream(int32_t channelCount);
void teardownAudioStream();
+ static int getDeviceSampleRate(int32_t channelCount);
+
bool openStream();
// Wave Sample Loading...