mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2025-07-23 13:15:45 +00:00
Move dead submodules in-tree
Signed-off-by: swurl <swurl@swurl.xyz>
This commit is contained in:
parent
c0cceff365
commit
6c655321e6
4081 changed files with 1185566 additions and 45 deletions
1
externals/oboe/samples/iolib/.gitignore
vendored
Normal file
1
externals/oboe/samples/iolib/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/build
|
35
externals/oboe/samples/iolib/README.md
vendored
Normal file
35
externals/oboe/samples/iolib/README.md
vendored
Normal 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)
|
34
externals/oboe/samples/iolib/build.gradle
vendored
Normal file
34
externals/oboe/samples/iolib/build.gradle
vendored
Normal 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'
|
||||
}
|
1
externals/oboe/samples/iolib/src/main/AndroidManifest.xml
vendored
Normal file
1
externals/oboe/samples/iolib/src/main/AndroidManifest.xml
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" />
|
62
externals/oboe/samples/iolib/src/main/cpp/CMakeLists.txt
vendored
Normal file
62
externals/oboe/samples/iolib/src/main/cpp/CMakeLists.txt
vendored
Normal 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)
|
36
externals/oboe/samples/iolib/src/main/cpp/player/DataSource.h
vendored
Normal file
36
externals/oboe/samples/iolib/src/main/cpp/player/DataSource.h
vendored
Normal 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_
|
82
externals/oboe/samples/iolib/src/main/cpp/player/OneShotSampleSource.cpp
vendored
Normal file
82
externals/oboe/samples/iolib/src/main/cpp/player/OneShotSampleSource.cpp
vendored
Normal 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
|
38
externals/oboe/samples/iolib/src/main/cpp/player/OneShotSampleSource.h
vendored
Normal file
38
externals/oboe/samples/iolib/src/main/cpp/player/OneShotSampleSource.h
vendored
Normal 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_
|
118
externals/oboe/samples/iolib/src/main/cpp/player/SampleBuffer.cpp
vendored
Normal file
118
externals/oboe/samples/iolib/src/main/cpp/player/SampleBuffer.cpp
vendored
Normal 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
|
57
externals/oboe/samples/iolib/src/main/cpp/player/SampleBuffer.h
vendored
Normal file
57
externals/oboe/samples/iolib/src/main/cpp/player/SampleBuffer.h
vendored
Normal 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_
|
21
externals/oboe/samples/iolib/src/main/cpp/player/SampleSource.cpp
vendored
Normal file
21
externals/oboe/samples/iolib/src/main/cpp/player/SampleSource.cpp
vendored
Normal 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
|
||||
}
|
106
externals/oboe/samples/iolib/src/main/cpp/player/SampleSource.h
vendored
Normal file
106
externals/oboe/samples/iolib/src/main/cpp/player/SampleSource.h
vendored
Normal 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_
|
224
externals/oboe/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp
vendored
Normal file
224
externals/oboe/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.cpp
vendored
Normal 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);
|
||||
}
|
||||
|
||||
}
|
119
externals/oboe/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.h
vendored
Normal file
119
externals/oboe/samples/iolib/src/main/cpp/player/SimpleMultiPlayer.h
vendored
Normal 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_
|
3
externals/oboe/samples/iolib/src/main/res/values/strings.xml
vendored
Normal file
3
externals/oboe/samples/iolib/src/main/res/values/strings.xml
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">iolib</string>
|
||||
</resources>
|
Loading…
Add table
Add a link
Reference in a new issue