Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/buffer classes and refactoring #116

Merged
merged 10 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions android/src/main/cpp/AudioBuffer/AudioBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ int AudioBuffer::getNumberOfChannels() {
return method(javaPart_);
}

int16_t **AudioBuffer::getChannelData(int channel) {
float **AudioBuffer::getChannelData(int channel) {
static const auto method =
javaClassStatic()->getMethod<JArrayShort(jint)>("getChannelData");
javaClassStatic()->getMethod<JArrayFloat(jint)>("getChannelData");
auto jArray = method(javaPart_, channel);
auto length = jArray->size();

auto channelData = new int16_t *[length];
auto channelData = new float *[length];
auto pin = jArray->pin();
for (int i = 0; i < length; i++) {
channelData[i] = &pin[i];
Expand All @@ -43,14 +43,14 @@ int16_t **AudioBuffer::getChannelData(int channel) {
return channelData;
}

void AudioBuffer::setChannelData(int channel, int16_t **data) {
void AudioBuffer::setChannelData(int channel, float **data) {
static const auto method =
javaClassStatic()->getMethod<void(jint, jshortArray)>("setChannelData");
std::vector<jshort> buffer(getLength());
javaClassStatic()->getMethod<void(jint, jfloatArray)>("setChannelData");
std::vector<jfloat> buffer(getLength());
for (int i = 0; i < getLength(); i++) {
buffer[i] = *data[i];
}
auto jArray = JArrayShort::newArray(getLength());
auto jArray = JArrayFloat::newArray(getLength());
jArray->setRegion(0, getLength(), buffer.data());

method(javaPart_, channel, jArray.get());
Expand Down
4 changes: 2 additions & 2 deletions android/src/main/cpp/AudioBuffer/AudioBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ class AudioBuffer : public jni::HybridClass<AudioBuffer> {
int getLength();
double getDuration();
int getNumberOfChannels();
int16_t **getChannelData(int channel);
void setChannelData(int channel, int16_t **data);
float **getChannelData(int channel);
void setChannelData(int channel, float **data);
void prepareForDeconstruction();

public:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class AudioContext : BaseAudioContext {
AudioFormat
.Builder()
.setSampleRate(this.sampleRate)
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setEncoding(AudioFormat.ENCODING_PCM_FLOAT)
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
.build()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class AudioBufferSourceNode(

init {
buffer = AudioBuffer(context.sampleRate, Constants.BUFFER_SIZE, 2)
playbackParameters = PlaybackParameters(context.getAudioTrack(Constants.BUFFER_SIZE), buffer)
val audioTrack = context.getAudioTrack(Constants.BUFFER_SIZE * 2)
playbackParameters = PlaybackParameters(audioTrack, buffer)
}

fun setBuffer(audioBuffer: AudioBuffer) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.swmansion.audioapi.nodes

import android.media.AudioTrack.WRITE_BLOCKING
import com.swmansion.audioapi.context.BaseAudioContext
import com.swmansion.audioapi.nodes.audionode.AudioNode
import com.swmansion.audioapi.nodes.audionode.ChannelCountMode
Expand All @@ -10,7 +11,6 @@ class AudioDestinationNode(
) : AudioNode(context) {
override val numberOfInputs = Float.POSITIVE_INFINITY.toInt()
override val numberOfOutputs = 0
override var channelCount: Int = 2
override val channelCountMode: ChannelCountMode = ChannelCountMode.EXPLICIT

private fun setVolumeAndPanning(playbackParameters: PlaybackParameters) {
Expand All @@ -21,13 +21,18 @@ class AudioDestinationNode(
mixBuffers(playbackParameters)

setVolumeAndPanning(playbackParameters)
val buffer = ShortArray(playbackParameters.audioBuffer.length * playbackParameters.audioBuffer.numberOfChannels)
val buffer = FloatArray(playbackParameters.audioBuffer.length * playbackParameters.audioBuffer.numberOfChannels)
for (i in 0 until playbackParameters.audioBuffer.length) {
for (j in 0 until playbackParameters.audioBuffer.numberOfChannels) {
buffer[i * playbackParameters.audioBuffer.numberOfChannels + j] = playbackParameters.audioBuffer.getChannelData(j)[i]
}
}

playbackParameters.audioTrack.write(buffer, 0, playbackParameters.audioBuffer.length * playbackParameters.audioBuffer.numberOfChannels)
playbackParameters.audioTrack.write(
buffer,
0,
playbackParameters.audioBuffer.length * playbackParameters.audioBuffer.numberOfChannels,
WRITE_BLOCKING,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ class GainNode(
) : AudioNode(context) {
override val numberOfInputs: Int = 1
override val numberOfOutputs: Int = 1
override var channelCount: Int = 2

private val gain: AudioParam = AudioParam(context, 1.0, Constants.MAX_GAIN, -Constants.MAX_GAIN)
get() = field
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ class StereoPannerNode(
) : AudioNode(context) {
override val numberOfInputs: Int = 1
override val numberOfOutputs: Int = 1
override var channelCount: Int = 2
override val channelCountMode: ChannelCountMode = ChannelCountMode.CLAMPED_MAX

private val pan: AudioParam = AudioParam(context, 0.0, Constants.MAX_PAN, -Constants.MAX_PAN)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ abstract class AudioNode(
get() = field
open val numberOfOutputs: Int = 0
get() = field
open var channelCount: Int = 1
open var channelCount: Int = 2
get() = field
open val channelCountMode: ChannelCountMode = ChannelCountMode.MAX
open val channelInterpretation: ChannelInterpretation = ChannelInterpretation.SPEAKERS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ class BiquadFilterNode(
) : AudioNode(context) {
override val numberOfInputs: Int = 1
override val numberOfOutputs: Int = 1
override var channelCount: Int = 2

private val frequency: AudioParam = AudioParam(context, 350.0, Constants.MAX_FILTER_FREQUENCY, Constants.MIN_FILTER_FREQUENCY)
get() = field
Expand Down Expand Up @@ -385,7 +384,7 @@ class BiquadFilterNode(
y1 = output

for (j in 0 until playbackParameters.audioBuffer.numberOfChannels) {
playbackParameters.audioBuffer.getChannelData(j)[i] = output.toInt().toShort()
playbackParameters.audioBuffer.getChannelData(j)[i] = output.toFloat()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import kotlin.math.pow
class OscillatorNode(
context: BaseAudioContext,
) : AudioScheduledSourceNode(context) {
override var channelCount = 2
override var playbackParameters: PlaybackParameters?

private val frequency: AudioParam = AudioParam(context, 440.0, Constants.NYQUIST_FREQUENCY, -Constants.NYQUIST_FREQUENCY)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,16 @@ enum class WaveType {
TRIANGLE,
;

private fun sineWave(wavePhase: Double): Short = (sin(wavePhase) * Short.MAX_VALUE).toInt().toShort()
private fun sineWave(wavePhase: Double): Float = sin(wavePhase).toFloat()

private fun squareWave(wavePhase: Double): Short = ((if (sin(wavePhase) >= 0) 1 else -1) * Short.MAX_VALUE).toShort()
private fun squareWave(wavePhase: Double): Float = (if (sin(wavePhase) >= 0) 1.0 else -1.0).toFloat()

private fun sawtoothWave(wavePhase: Double): Short =
((2 * (wavePhase / (2 * Math.PI) - floor(wavePhase / (2 * Math.PI) + 0.5))) * Short.MAX_VALUE).toInt().toShort()
private fun sawtoothWave(wavePhase: Double): Float = (2 * (wavePhase / (2 * Math.PI) - floor(wavePhase / (2 * Math.PI) + 0.5))).toFloat()

private fun triangleWave(wavePhase: Double): Short =
((2 * abs(2 * (wavePhase / (2 * Math.PI) - floor(wavePhase / (2 * Math.PI) + 0.5))) - 1) * Short.MAX_VALUE).toInt().toShort()
private fun triangleWave(wavePhase: Double): Float =
(2 * abs(2 * (wavePhase / (2 * Math.PI) - floor(wavePhase / (2 * Math.PI) + 0.5))) - 1).toFloat()

private fun getWaveValue(wavePhase: Double): Short =
private fun getWaveValue(wavePhase: Double): Float =
when (this) {
SINE -> sineWave(wavePhase)
SQUARE -> squareWave(wavePhase)
Expand Down Expand Up @@ -50,6 +49,6 @@ enum class WaveType {
fun getWaveBufferElement(
wavePhase: Double,
waveType: WaveType,
): Short = waveType.getWaveValue(wavePhase)
): Float = waveType.getWaveValue(wavePhase)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class AudioBuffer(
get() = field
val numberOfChannels: Int = numberOfChannels
get() = field
private val channels: Array<ShortArray> = Array(numberOfChannels) { ShortArray(length) }
private val channels: Array<FloatArray> = Array(numberOfChannels) { FloatArray(length) }

private val mHybridData: HybridData?

Expand All @@ -31,7 +31,7 @@ class AudioBuffer(

external fun initHybrid(): HybridData?

fun getChannelData(channel: Int): ShortArray {
fun getChannelData(channel: Int): FloatArray {
if (channel < 0 || channel >= numberOfChannels) {
throw IllegalArgumentException("Channel index out of bounds")
}
Expand All @@ -41,7 +41,7 @@ class AudioBuffer(

private fun setChannelData(
channel: Int,
data: ShortArray,
data: FloatArray,
) {
if (channel < 0 || channel >= numberOfChannels) {
throw IllegalArgumentException("Channel index out of bounds")
Expand Down Expand Up @@ -82,10 +82,10 @@ class AudioBuffer(
2 -> {
if (outputNumberOfChannels == 1) {
val outputBuffer = AudioBuffer(sampleRate, length, 1)
val outputData = ShortArray(length)
val outputData = FloatArray(length)

for (i in 0 until length) {
outputData[i] = ((channels[0][i] + channels[1][i]) / 2).toShort()
outputData[i] = (channels[0][i] + channels[1][i]) / 2
}

return outputBuffer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import kotlin.math.log2

object Constants {
const val SAMPLE_RATE: Int = 44100
const val BUFFER_SIZE = 100
const val BUFFER_SIZE = 128

private const val MOST_POSITIVE_SINGLE_FLOAT: Double = (Float.MAX_VALUE).toDouble()
const val NYQUIST_FREQUENCY: Double = SAMPLE_RATE / 2.0
Expand Down
8 changes: 4 additions & 4 deletions common/cpp/AudioBuffer/AudioBufferHostObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jsi::Value AudioBufferHostObject::get(
const jsi::Value *args,
size_t count) -> jsi::Value {
int channel = args[0].getNumber();
int16_t **channelData = wrapper_->getChannelData(channel);
float **channelData = wrapper_->getChannelData(channel);

auto array = jsi::Array(rt, wrapper_->getLength());
for (int i = 0; i < wrapper_->getLength(); i++) {
Expand All @@ -72,14 +72,14 @@ jsi::Value AudioBufferHostObject::get(
size_t count) -> jsi::Value {
int channel = args[0].getNumber();
auto array = args[1].getObject(rt).asArray(rt);
auto **channelData = new int16_t *[wrapper_->getLength()];
auto **channelData = new float *[wrapper_->getLength()];

for (int i = 0; i < wrapper_->getLength(); i++) {
channelData[i] =
new int16_t(array.getValueAtIndex(rt, i).getNumber() * 32767);
new float(array.getValueAtIndex(rt, i).getNumber());
}

wrapper_->setChannelData(channel, channelData);
wrapper_->setChannelData(channel, channelData, wrapper_->getLength());

return jsi::Value::undefined();
});
Expand Down
9 changes: 6 additions & 3 deletions common/cpp/AudioBuffer/AudioBufferWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifdef ANDROID
#include "AudioBuffer.h"
#else
#include "IOSAudioBuffer.h"
#endif

namespace audioapi {
Expand All @@ -20,7 +21,9 @@ class AudioBufferWrapper {
#else

public:
AudioBufferWrapper() {}
std::shared_ptr<IOSAudioBuffer> audioBuffer_;

explicit AudioBufferWrapper(std::shared_ptr<IOSAudioBuffer> audioBuffer);
#endif

private:
Expand All @@ -34,7 +37,7 @@ class AudioBufferWrapper {
int getLength() const;
double getDuration() const;
int getNumberOfChannels() const;
int16_t **getChannelData(int channel) const;
void setChannelData(int channel, int16_t **data) const;
float **getChannelData(int channel) const;
void setChannelData(int channel, float **data, int length) const;
};
} // namespace audioapi
7 changes: 4 additions & 3 deletions common/cpp/AudioBuffer/android/AudioBufferWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ int AudioBufferWrapper::getNumberOfChannels() const {
return numberOfChannels;
}

int16_t **AudioBufferWrapper::getChannelData(int channel) const {
float **AudioBufferWrapper::getChannelData(int channel) const {
return audioBuffer_->getChannelData(channel);
}

void AudioBufferWrapper::setChannelData(int channel, int16_t **data) const {
audioBuffer_->setChannelData(channel, data);
void AudioBufferWrapper::setChannelData(int channel, float **data, int length)
const {
audioBuffer_->setChannelData(channel, data, length);
}
} // namespace audioapi
#endif
26 changes: 17 additions & 9 deletions common/cpp/AudioBuffer/ios/AudioBufferWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,38 @@

namespace audioapi {

// TODO: Implement the AudioParamWrapper class
AudioBufferWrapper::AudioBufferWrapper(
std::shared_ptr<IOSAudioBuffer> audioBuffer) {
audioBuffer_ = audioBuffer;
sampleRate = audioBuffer->getSampleRate();
length = audioBuffer->getLength();
duration = audioBuffer->getDuration();
numberOfChannels = audioBuffer->getNumberOfChannels();
}

int AudioBufferWrapper::getSampleRate() const {
return 1;
return sampleRate;
}

int AudioBufferWrapper::getLength() const {
return 1;
return length;
}

double AudioBufferWrapper::getDuration() const {
return 1.0;
return duration;
}

int AudioBufferWrapper::getNumberOfChannels() const {
return 1;
return numberOfChannels;
}

int16_t **AudioBufferWrapper::getChannelData(int channel) const {
return nullptr;
float **AudioBufferWrapper::getChannelData(int channel) const {
return audioBuffer_->getChannelData(channel);
}

void AudioBufferWrapper::setChannelData(int channel, int16_t **data) const {
return;
void AudioBufferWrapper::setChannelData(int channel, float **data, int length)
const {
audioBuffer_->setChannelData(channel, data, length);
}

} // namespace audioapi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#ifdef ANDROID
#include "AudioBufferSourceNode.h"
#else
#include "IOSAudioBufferSourceNode.h"
#endif

namespace audioapi {
Expand All @@ -26,8 +27,14 @@ class AudioBufferSourceNodeWrapper : public AudioNodeWrapper {
: AudioNodeWrapper(audioBufferNode) {}
#else

private:
std::shared_ptr<IOSAudioBufferSourceNode>
getAudioBufferSourceNodeFromAudioNode();

public:
AudioBufferSourceNodeWrapper() : AudioNodeWrapper() {}
AudioBufferSourceNodeWrapper(
std::shared_ptr<IOSAudioBufferSourceNode> bufferSourceNode)
: AudioNodeWrapper(bufferSourceNode) {}
#endif

public:
Expand Down
Loading
Loading