Move dead submodules in-tree

Signed-off-by: swurl <swurl@swurl.xyz>
This commit is contained in:
swurl 2025-05-31 02:33:02 -04:00
parent c0cceff365
commit 6c655321e6
No known key found for this signature in database
GPG key ID: A5A7629F109C8FD1
4081 changed files with 1185566 additions and 45 deletions

View file

@ -0,0 +1 @@
/build

35
externals/oboe/samples/iolib/README.md vendored Normal file
View file

@ -0,0 +1,35 @@
**iolib**
==========
Classes for playing audio data.
## Abstract
(Oboe) **iolib** contains classes implementing streaming audio playback and mixing from multiple sources. It's purpose is to demonstrate best practices and provide reusable code.
Note: the more general name of "iolib" was chosen since it is presumed that this project will eventually implement audio capture capability.
**iolib** is written in C++ and is intended to be called from Android native code. It is implemented as a static library.
# **iolib** project structure
* player
Contains classes to support streaming playback from (potentially) multiple audio sources.
## player classes
### DataSource
Declares the basic interface for audio data sources.
### SampleSource
Extends the `DataSource` interface for audio data coming from SampleBuffer objects.
### OneShotSampleSource
Extends `SampleSource` to provide data that plays through it's `SampleBuffer` and then provides silence, (i.e. a non-looping sample)
### SampleBuffer
Loads and holds (in memory) audio sample data and provides read-only access to that data.
### SimpleMultiPlayer
Implements an Oboe audio stream into which it mixes audio from some number of `SampleSource`s.
This class demonstrates:
* Creation and lifetime management of an Oboe audio stream (`ManagedStream`)
* Logic for an Oboe `AudioStreamCallback` interface.
* Logic for handling streaming restart on error (i.e. playback device changes)

View file

@ -0,0 +1,34 @@
apply plugin: 'com.android.library'
android {
defaultConfig {
minSdkVersion 21
targetSdkVersion 35
compileSdkVersion 35
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_18
targetCompatibility JavaVersion.VERSION_18
}
externalNativeBuild {
cmake {
path 'src/main/cpp/CMakeLists.txt'
}
}
namespace 'com.google.oboe.samples.iolib'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.7.0'
}

View file

@ -0,0 +1 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />

View file

@ -0,0 +1,62 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
#PROJECT(wavlib C CXX)
#message("CMAKE_CURRENT_LIST_DIR = " ${CMAKE_CURRENT_LIST_DIR})
#message("HOME is " ${HOME})
# SET(NDK "")
#message("NDK is " ${NDK})
# Set the path to the Oboe library directory
set (OBOE_DIR ../../../../../)
#message("OBOE_DIR = " + ${OBOE_DIR})
# Pull in parselib
set (PARSELIB_DIR ../../../../parselib)
#message("PARSELIB_DIR = " + ${PARSELIB_DIR})
# compiler flags
# -mhard-float -D_NDK_MATH_NO_SOFTFP=1
#SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mhard-float -D_NDK_MATH_NO_SOFTFP=1" )
# include folders
include_directories(
${PARSELIB_DIR}/src/main/cpp
${OBOE_DIR}/include
${OBOE_DIR}/src/flowgraph
${CMAKE_CURRENT_LIST_DIR}
../../../../shared)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
add_library( # Sets the name of the library.
iolib
# Sets the library as a static library.
STATIC
# source
${CMAKE_CURRENT_LIST_DIR}/player/SampleSource.cpp
${CMAKE_CURRENT_LIST_DIR}/player/SampleBuffer.cpp
${CMAKE_CURRENT_LIST_DIR}/player/OneShotSampleSource.cpp
${CMAKE_CURRENT_LIST_DIR}/player/SimpleMultiPlayer.cpp)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
iolib
# Links the target library to the log library
# included in the NDK.
log)

View file

@ -0,0 +1,36 @@
/*
* Copyright (C) 2019 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 _PLAYER_AUDIOSOURCE_H_
#define _PLAYER_AUDIOSOURCE_H_
#include <cstdint>
namespace iolib {
/*
* Defines an interface for audio data sources for the SimpleMultiPlayer class.
*/
class DataSource {
public:
virtual ~DataSource() {};
virtual void mixAudio(float* outBuff, int numChannels, int numFrames) = 0;
};
}
#endif //_PLAYER_AUDIOSOURCE_H_

View file

@ -0,0 +1,82 @@
/*
* Copyright (C) 2019 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 <string.h>
#include "wav/WavStreamReader.h"
#include "OneShotSampleSource.h"
namespace iolib {
void OneShotSampleSource::mixAudio(float* outBuff, int numChannels, int32_t numFrames) {
int32_t numSamples = mSampleBuffer->getNumSamples();
int32_t sampleChannels = mSampleBuffer->getProperties().channelCount;
int32_t totalSamplesNeeded = numFrames * numChannels; // Total samples to fill the output buffer
int32_t samplesProcessed = 0;
bool isLoopMode = mIsLoopMode;
while (samplesProcessed < totalSamplesNeeded && mIsPlaying) {
int32_t samplesLeft = numSamples - mCurSampleIndex;
int32_t framesLeft = (totalSamplesNeeded - samplesProcessed) / numChannels;
int32_t numWriteFrames = std::min(framesLeft, samplesLeft / sampleChannels);
if (numWriteFrames > 0) {
const float* data = mSampleBuffer->getSampleData();
if ((sampleChannels == 1) && (numChannels == 1)) {
// MONO output from MONO samples
for (int32_t frameIndex = 0; frameIndex < numWriteFrames; frameIndex++) {
outBuff[samplesProcessed + frameIndex] += data[mCurSampleIndex++] * mGain;
}
} else if ((sampleChannels == 1) && (numChannels == 2)) {
// STEREO output from MONO samples
int dstSampleIndex = samplesProcessed;
for (int32_t frameIndex = 0; frameIndex < numWriteFrames; frameIndex++) {
outBuff[dstSampleIndex++] += data[mCurSampleIndex] * mLeftGain;
outBuff[dstSampleIndex++] += data[mCurSampleIndex++] * mRightGain;
}
} else if ((sampleChannels == 2) && (numChannels == 1)) {
// MONO output from STEREO samples
int dstSampleIndex = samplesProcessed;
for (int32_t frameIndex = 0; frameIndex < numWriteFrames; frameIndex++) {
outBuff[dstSampleIndex++] += data[mCurSampleIndex++] * mLeftGain +
data[mCurSampleIndex++] * mRightGain;
}
} else if ((sampleChannels == 2) && (numChannels == 2)) {
// STEREO output from STEREO samples
int dstSampleIndex = samplesProcessed;
for (int32_t frameIndex = 0; frameIndex < numWriteFrames; frameIndex++) {
outBuff[dstSampleIndex++] += data[mCurSampleIndex++] * mLeftGain;
outBuff[dstSampleIndex++] += data[mCurSampleIndex++] * mRightGain;
}
}
samplesProcessed += numWriteFrames * numChannels;
if (mCurSampleIndex >= numSamples) {
if (isLoopMode) {
mCurSampleIndex = 0;
} else {
mIsPlaying = false;
}
}
} else {
break; // No more samples to write in the current chunk
}
}
}
} // namespace wavlib

View file

@ -0,0 +1,38 @@
/*
* Copyright (C) 2019 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 _PLAYER_ONESHOTSAMPLESOURCE_
#define _PLAYER_ONESHOTSAMPLESOURCE_
#include "SampleSource.h"
namespace iolib {
/**
* Provides audio data which will play through ONCE when triggered
* Currently the sample data is assumed to be MONO
*/
class OneShotSampleSource: public SampleSource {
public:
OneShotSampleSource(SampleBuffer *sampleBuffer, float pan) : SampleSource(sampleBuffer, pan) {};
virtual ~OneShotSampleSource() {};
virtual void mixAudio(float* outBuff, int numChannels, int32_t numFrames);
};
} // namespace iolib
#endif //_PLAYER_ONESHOTSAMPLESOURCE_

View file

@ -0,0 +1,118 @@
/*
* Copyright (C) 2020 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 "SampleBuffer.h"
// Resampler Includes
#include <resampler/MultiChannelResampler.h>
#include "wav/WavStreamReader.h"
using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
namespace iolib {
void SampleBuffer::loadSampleData(parselib::WavStreamReader* reader) {
mAudioProperties.channelCount = reader->getNumChannels();
mAudioProperties.sampleRate = reader->getSampleRate();
reader->positionToAudio();
mNumSamples = reader->getNumSampleFrames() * reader->getNumChannels();
mSampleData = new float[mNumSamples];
reader->getDataFloat(mSampleData, reader->getNumSampleFrames());
}
void SampleBuffer::unloadSampleData() {
if (mSampleData != nullptr) {
delete[] mSampleData;
mSampleData = nullptr;
}
mNumSamples = 0;
}
class ResampleBlock {
public:
int32_t mSampleRate;
float* mBuffer;
int32_t mNumSamples;
};
void resampleData(const ResampleBlock& input, ResampleBlock* output, int numChannels) {
// Calculate output buffer size
double temp =
((double)input.mNumSamples * (double)output->mSampleRate) / (double)input.mSampleRate;
// round up
int32_t numOutFramesAllocated = (int32_t)(temp + 0.5);
// We iterate thousands of times through the loop. Roundoff error could accumulate
// so add a few more frames for padding
numOutFramesAllocated += 8;
MultiChannelResampler *resampler = MultiChannelResampler::make(
numChannels, // 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[numOutFramesAllocated]; // multi-channel buffer to be filled
output->mBuffer = outputBuffer;
int numOutputSamples = 0;
int inputSamplesLeft = input.mNumSamples;
while ((inputSamplesLeft > 0) && (numOutputSamples < numOutFramesAllocated)) {
if(resampler->isWriteNeeded()) {
resampler->writeNextFrame(inputBuffer);
inputBuffer += numChannels;
inputSamplesLeft -= numChannels;
} else {
resampler->readNextFrame(outputBuffer);
outputBuffer += numChannels;
numOutputSamples += numChannels;
}
}
output->mNumSamples = numOutputSamples;
delete resampler;
}
void SampleBuffer::resampleData(int sampleRate) {
if (mAudioProperties.sampleRate == sampleRate) {
// nothing to do
return;
}
ResampleBlock inputBlock;
inputBlock.mBuffer = mSampleData;
inputBlock.mNumSamples = mNumSamples;
inputBlock.mSampleRate = mAudioProperties.sampleRate;
ResampleBlock outputBlock;
outputBlock.mSampleRate = sampleRate;
iolib::resampleData(inputBlock, &outputBlock, mAudioProperties.channelCount);
// delete previous samples
delete[] mSampleData;
// install the resampled data
mSampleData = outputBlock.mBuffer;
mNumSamples = outputBlock.mNumSamples;
mAudioProperties.sampleRate = outputBlock.mSampleRate;
}
} // namespace iolib

View file

@ -0,0 +1,57 @@
/*
* Copyright (C) 2020 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 _PLAYER_SAMPLEBUFFER_
#define _PLAYER_SAMPLEBUFFER_
#include <wav/WavStreamReader.h>
namespace iolib {
/*
* Defines the relevant properties of the audio data being sourced.
*/
struct AudioProperties {
int32_t channelCount;
int32_t sampleRate;
};
class SampleBuffer {
public:
SampleBuffer() : mNumSamples(0) {};
~SampleBuffer() { unloadSampleData(); }
// Data load/unload
void loadSampleData(parselib::WavStreamReader* reader);
void unloadSampleData();
void resampleData(int sampleRate);
virtual AudioProperties getProperties() const { return mAudioProperties; }
float* getSampleData() { return mSampleData; }
int32_t getNumSamples() { return mNumSamples; }
protected:
AudioProperties mAudioProperties;
float* mSampleData;
int32_t mNumSamples;
};
}
#endif //_PLAYER_SAMPLEBUFFER_

View file

@ -0,0 +1,21 @@
/*
* Copyright (C) 2020 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 "SampleSource.h"
namespace iolib {
// for now, all methods of SampleSource are either in-line or pure virtual
}

View file

@ -0,0 +1,106 @@
/*
* Copyright (C) 2020 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 _PLAYER_SAMPLESOURCE_
#define _PLAYER_SAMPLESOURCE_
#include <cstdint>
#include "DataSource.h"
#include "SampleBuffer.h"
namespace iolib {
/**
* Defines an interface for audio data provided to a player object.
* Concrete examples include OneShotSampleBuffer. One could imagine a LoopingSampleBuffer.
* Supports stereo position via mPan member.
*/
class SampleSource: public DataSource {
public:
// Pan position of the audio in a stereo mix
// [left:-1.0f] <- [center: 0.0f] -> -[right: 1.0f]
static constexpr float PAN_HARDLEFT = -1.0f;
static constexpr float PAN_HARDRIGHT = 1.0f;
static constexpr float PAN_CENTER = 0.0f;
SampleSource(SampleBuffer *sampleBuffer, float pan)
: mSampleBuffer(sampleBuffer), mCurSampleIndex(0), mIsPlaying(false), mIsLoopMode(false), mGain(1.0f) {
setPan(pan);
}
virtual ~SampleSource() {}
void setPlayMode() { mCurSampleIndex = 0; mIsPlaying = true; }
void setStopMode() { mIsPlaying = false; mCurSampleIndex = 0; }
void setLoopMode(bool isLoopMode) { mIsLoopMode = isLoopMode; }
bool isPlaying() { return mIsPlaying; }
void setPan(float pan) {
if (pan < PAN_HARDLEFT) {
mPan = PAN_HARDLEFT;
} else if (pan > PAN_HARDRIGHT) {
mPan = PAN_HARDRIGHT;
} else {
mPan = pan;
}
calcGainFactors();
}
float getPan() {
return mPan;
}
void setGain(float gain) {
mGain = gain;
calcGainFactors();
}
float getGain() {
return mGain;
}
protected:
SampleBuffer *mSampleBuffer;
int32_t mCurSampleIndex;
bool mIsPlaying;
std::atomic<bool> mIsLoopMode;
// Logical pan value
float mPan;
// precomputed channel gains for pan
float mLeftGain;
float mRightGain;
// Overall gain
float mGain;
private:
void calcGainFactors() {
// useful panning information: http://www.cs.cmu.edu/~music/icm-online/readings/panlaws/
float rightPan = (mPan * 0.5) + 0.5;
mRightGain = rightPan * mGain;
mLeftGain = (1.0 - rightPan) * mGain; }
};
} // namespace wavlib
#endif //_PLAYER_SAMPLESOURCE_

View file

@ -0,0 +1,224 @@
/*
* Copyright 2019 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 <android/log.h>
// parselib includes
#include <stream/MemInputStream.h>
#include <wav/WavStreamReader.h>
// local includes
#include "OneShotSampleSource.h"
#include "SimpleMultiPlayer.h"
static const char* TAG = "SimpleMultiPlayer";
using namespace oboe;
using namespace parselib;
namespace iolib {
constexpr int32_t kBufferSizeInBursts = 2; // Use 2 bursts as the buffer size (double buffer)
SimpleMultiPlayer::SimpleMultiPlayer()
: mChannelCount(0), mOutputReset(false), mSampleRate(0), mNumSampleBuffers(0)
{}
DataCallbackResult SimpleMultiPlayer::MyDataCallback::onAudioReady(AudioStream *oboeStream,
void *audioData,
int32_t numFrames) {
StreamState streamState = oboeStream->getState();
if (streamState != StreamState::Open && streamState != StreamState::Started) {
__android_log_print(ANDROID_LOG_ERROR, TAG, " streamState:%d", streamState);
}
if (streamState == StreamState::Disconnected) {
__android_log_print(ANDROID_LOG_ERROR, TAG, " streamState::Disconnected");
}
memset(audioData, 0, static_cast<size_t>(numFrames) * static_cast<size_t>
(mParent->mChannelCount) * sizeof(float));
// OneShotSampleSource* sources = mSampleSources.get();
for(int32_t index = 0; index < mParent->mNumSampleBuffers; index++) {
if (mParent->mSampleSources[index]->isPlaying()) {
mParent->mSampleSources[index]->mixAudio((float*)audioData, mParent->mChannelCount,
numFrames);
}
}
return DataCallbackResult::Continue;
}
void SimpleMultiPlayer::MyErrorCallback::onErrorAfterClose(AudioStream *oboeStream, Result error) {
__android_log_print(ANDROID_LOG_INFO, TAG, "==== onErrorAfterClose() error:%d", error);
mParent->resetAll();
if (mParent->openStream() && mParent->startStream()) {
mParent->mOutputReset = true;
}
}
bool SimpleMultiPlayer::openStream() {
__android_log_print(ANDROID_LOG_INFO, TAG, "openStream()");
// Use shared_ptr to prevent use of a deleted callback.
mDataCallback = std::make_shared<MyDataCallback>(this);
mErrorCallback = std::make_shared<MyErrorCallback>(this);
// Create an audio stream
AudioStreamBuilder builder;
builder.setChannelCount(mChannelCount);
// we will resample source data to device rate, so take default sample rate
builder.setDataCallback(mDataCallback);
builder.setErrorCallback(mErrorCallback);
builder.setPerformanceMode(PerformanceMode::LowLatency);
builder.setSharingMode(SharingMode::Exclusive);
builder.setSampleRateConversionQuality(SampleRateConversionQuality::Medium);
Result result = builder.openStream(mAudioStream);
if (result != Result::OK){
__android_log_print(
ANDROID_LOG_ERROR,
TAG,
"openStream failed. Error: %s", convertToText(result));
return false;
}
// Reduce stream latency by setting the buffer size to a multiple of the burst size
// Note: this will fail with ErrorUnimplemented if we are using a callback with OpenSL ES
// See oboe::AudioStreamBuffered::setBufferSizeInFrames
result = mAudioStream->setBufferSizeInFrames(
mAudioStream->getFramesPerBurst() * kBufferSizeInBursts);
if (result != Result::OK) {
__android_log_print(
ANDROID_LOG_WARN,
TAG,
"setBufferSizeInFrames failed. Error: %s", convertToText(result));
}
mSampleRate = mAudioStream->getSampleRate();
return true;
}
bool SimpleMultiPlayer::startStream() {
int tryCount = 0;
while (tryCount < 3) {
bool wasOpenSuccessful = true;
// Assume that openStream() was called successfully before startStream() call.
if (tryCount > 0) {
usleep(20 * 1000); // Sleep between tries to give the system time to settle.
wasOpenSuccessful = openStream(); // Try to open the stream again after the first try.
}
if (wasOpenSuccessful) {
Result result = mAudioStream->requestStart();
if (result != Result::OK){
__android_log_print(
ANDROID_LOG_ERROR,
TAG,
"requestStart failed. Error: %s", convertToText(result));
mAudioStream->close();
mAudioStream.reset();
} else {
return true;
}
}
tryCount++;
}
return false;
}
void SimpleMultiPlayer::setupAudioStream(int32_t channelCount) {
__android_log_print(ANDROID_LOG_INFO, TAG, "setupAudioStream()");
mChannelCount = channelCount;
openStream();
}
void SimpleMultiPlayer::teardownAudioStream() {
__android_log_print(ANDROID_LOG_INFO, TAG, "teardownAudioStream()");
// tear down the player
if (mAudioStream) {
mAudioStream->stop();
mAudioStream->close();
mAudioStream.reset();
}
}
void SimpleMultiPlayer::addSampleSource(SampleSource* source, SampleBuffer* buffer) {
buffer->resampleData(mSampleRate);
mSampleBuffers.push_back(buffer);
mSampleSources.push_back(source);
mNumSampleBuffers++;
}
void SimpleMultiPlayer::unloadSampleData() {
__android_log_print(ANDROID_LOG_INFO, TAG, "unloadSampleData()");
resetAll();
for (int32_t bufferIndex = 0; bufferIndex < mNumSampleBuffers; bufferIndex++) {
delete mSampleBuffers[bufferIndex];
delete mSampleSources[bufferIndex];
}
mSampleBuffers.clear();
mSampleSources.clear();
mNumSampleBuffers = 0;
}
void SimpleMultiPlayer::triggerDown(int32_t index) {
if (index < mNumSampleBuffers) {
mSampleSources[index]->setPlayMode();
}
}
void SimpleMultiPlayer::triggerUp(int32_t index) {
if (index < mNumSampleBuffers) {
mSampleSources[index]->setStopMode();
}
}
void SimpleMultiPlayer::resetAll() {
for (int32_t bufferIndex = 0; bufferIndex < mNumSampleBuffers; bufferIndex++) {
mSampleSources[bufferIndex]->setStopMode();
}
}
void SimpleMultiPlayer::setPan(int index, float pan) {
mSampleSources[index]->setPan(pan);
}
float SimpleMultiPlayer::getPan(int index) {
return mSampleSources[index]->getPan();
}
void SimpleMultiPlayer::setGain(int index, float gain) {
mSampleSources[index]->setGain(gain);
}
float SimpleMultiPlayer::getGain(int index) {
return mSampleSources[index]->getGain();
}
void SimpleMultiPlayer::setLoopMode(int index, bool isLoopMode) {
mSampleSources[index]->setLoopMode(isLoopMode);
}
}

View file

@ -0,0 +1,119 @@
/*
* Copyright 2019 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 _PLAYER_SIMPLEMULTIPLAYER_H_
#define _PLAYER_SIMPLEMULTIPLAYER_H_
#include <vector>
#include <oboe/Oboe.h>
#include "OneShotSampleSource.h"
#include "SampleBuffer.h"
namespace iolib {
/**
* A simple streaming player for multiple SampleBuffers.
*/
class SimpleMultiPlayer {
public:
SimpleMultiPlayer();
void setupAudioStream(int32_t channelCount);
void teardownAudioStream();
bool openStream();
bool startStream();
int getSampleRate() { return mSampleRate; }
// Wave Sample Loading...
/**
* Adds the SampleSource/SampleBuffer pair to the list of source channels.
* Transfers ownership of those objects so that they can be deleted/unloaded.
* The indexes associated with each source channel is the order in which they
* are added.
*/
void addSampleSource(SampleSource* source, SampleBuffer* buffer);
/**
* Deallocates and deletes all added source/buffer (see addSampleSource()).
*/
void unloadSampleData();
void triggerDown(int32_t index);
void triggerUp(int32_t index);
void resetAll();
bool getOutputReset() { return mOutputReset; }
void clearOutputReset() { mOutputReset = false; }
void setPan(int index, float pan);
float getPan(int index);
void setGain(int index, float gain);
float getGain(int index);
void setLoopMode(int index, bool isLoopMode);
private:
class MyDataCallback : public oboe::AudioStreamDataCallback {
public:
MyDataCallback(SimpleMultiPlayer *parent) : mParent(parent) {}
oboe::DataCallbackResult onAudioReady(
oboe::AudioStream *audioStream,
void *audioData,
int32_t numFrames) override;
private:
SimpleMultiPlayer *mParent;
};
class MyErrorCallback : public oboe::AudioStreamErrorCallback {
public:
MyErrorCallback(SimpleMultiPlayer *parent) : mParent(parent) {}
virtual ~MyErrorCallback() {
}
void onErrorAfterClose(oboe::AudioStream *oboeStream, oboe::Result error) override;
private:
SimpleMultiPlayer *mParent;
};
// Oboe Audio Stream
std::shared_ptr<oboe::AudioStream> mAudioStream;
// Playback Audio attributes
int32_t mChannelCount;
int32_t mSampleRate;
// Sample Data
int32_t mNumSampleBuffers;
std::vector<SampleBuffer*> mSampleBuffers;
std::vector<SampleSource*> mSampleSources;
bool mOutputReset;
std::shared_ptr<MyDataCallback> mDataCallback;
std::shared_ptr<MyErrorCallback> mErrorCallback;
};
}
#endif //_PLAYER_SIMPLEMULTIPLAYER_H_

View file

@ -0,0 +1,3 @@
<resources>
<string name="app_name">iolib</string>
</resources>