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/android/audio node #38

Merged
merged 2 commits into from
Jul 23, 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
6 changes: 6 additions & 0 deletions android/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ include_directories(
../cpp/AudioContext
../cpp/AudioDestinationNode
../cpp/OscillatorNode
../cpp/AudioNode
src/main/cpp
../node_modules/react-native/ReactCommon/jsi
../node_modules/react-native/ReactAndroid/src/main/jni/react/jni
Expand All @@ -27,6 +28,7 @@ add_library(react-native-audio-context SHARED
src/main/cpp/AudioContext
src/main/cpp/OscillatorNode
src/main/cpp/AudioDestinationNode
src/main/cpp/AudioNode

../cpp/AudioContext/AudioContextHostObject
../cpp/AudioContext/AudioContextWrapper.h
Expand All @@ -39,6 +41,10 @@ add_library(react-native-audio-context SHARED
../cpp/OscillatorNode/OscillatorNodeHostObject
../cpp/OscillatorNode/OscillatorNodeWrapper.h
../cpp/OscillatorNode/android/OscillatorNodeWrapper.cpp

../cpp/AudioNode/AudioNodeHostObject.h
../cpp/AudioNode/AudioNodeWrapper.h
../cpp/AudioNode/android/AudioNodeWrapper.cpp
)

find_package(ReactAndroid REQUIRED CONFIG)
Expand Down
2 changes: 0 additions & 2 deletions android/src/main/cpp/AudioDestinationNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,4 @@ namespace audiocontext {

using namespace facebook::jni;

AudioDestinationNode::AudioDestinationNode(jni::alias_ref<AudioDestinationNode::jhybridobject> &jThis): javaObject_(make_global(jThis)) {}

} // namespace audiocontext
21 changes: 1 addition & 20 deletions android/src/main/cpp/AudioDestinationNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,9 @@ namespace audiocontext {

class OscillatorNode;

class AudioDestinationNode : public jni::HybridClass<AudioDestinationNode> {
class AudioDestinationNode : public jni::HybridClass<AudioDestinationNode, AudioNode> {
public:
static auto constexpr kJavaDescriptor = "Lcom/audiocontext/nodes/AudioDestinationNode;";

static jni::local_ref<AudioDestinationNode::jhybriddata> initHybrid(jni::alias_ref<jhybridobject> jThis)
{
return makeCxxInstance(jThis);
}

static void registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", AudioDestinationNode::initHybrid),
});
}

private:
friend HybridBase;
friend class OscillatorNode;

global_ref<AudioDestinationNode::javaobject> javaObject_;

explicit AudioDestinationNode(jni::alias_ref<AudioDestinationNode::jhybridobject>& jThis);
};

} // namespace audiocontext
18 changes: 18 additions & 0 deletions android/src/main/cpp/AudioNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "AudioNode.h"

namespace audiocontext {

AudioNode::AudioNode(alias_ref<AudioNode::jhybridobject> &jThis): javaObject_(make_global(jThis)) {}

void AudioNode::connect(const std::shared_ptr<AudioNode> node) {
static const auto method = javaClassLocal()->getMethod<void(AudioNode::javaobject)>(
"connect");
method(javaObject_.get(), node->javaObject_.get());
}

void AudioNode::disconnect(const std::shared_ptr<AudioNode> node) {
static const auto method = javaClassLocal()->getMethod<void(AudioNode::javaobject)>(
"disconnect");
method(javaObject_.get(), node->javaObject_.get());
}
}
40 changes: 40 additions & 0 deletions android/src/main/cpp/AudioNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once

#include <fbjni/fbjni.h>
#include <react/jni/CxxModuleWrapper.h>
#include <react/jni/JMessageQueueThread.h>
#include <memory>

namespace audiocontext {

using namespace facebook;
using namespace facebook::jni;

class AudioNode : public jni::HybridClass<AudioNode> {
public:
static auto constexpr kJavaDescriptor = "Lcom/audiocontext/nodes/AudioNode;";

static jni::local_ref<AudioNode::jhybriddata> initHybrid(jni::alias_ref<jhybridobject> jThis)
{
return makeCxxInstance(jThis);
}

static void registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", AudioNode::initHybrid),
});
}

void connect(const std::shared_ptr<AudioNode> node);
void disconnect(const std::shared_ptr<AudioNode> node);

protected:
friend HybridBase;
friend class AudioNode;

global_ref<AudioNode::javaobject> javaObject_;

explicit AudioNode(jni::alias_ref<AudioNode::jhybridobject>& jThis);
};

} // namespace audiocontext
2 changes: 2 additions & 0 deletions android/src/main/cpp/OnLoad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "OscillatorNode.h"
#include "AudioContext.h"
#include "AudioDestinationNode.h"
#include "AudioNode.h"

using namespace audiocontext;

Expand All @@ -11,5 +12,6 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
OscillatorNode::registerNatives();
AudioContext::registerNatives();
AudioDestinationNode::registerNatives();
AudioNode::registerNatives();
});
}
8 changes: 0 additions & 8 deletions android/src/main/cpp/OscillatorNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ namespace audiocontext {

using namespace facebook::jni;

OscillatorNode::OscillatorNode(jni::alias_ref<OscillatorNode::jhybridobject> &jThis)
: javaObject_(make_global(jThis)){}

void OscillatorNode::start(double time) {
static const auto method = javaClassLocal()->getMethod<void(jdouble)>("start");
method(javaObject_.get(), time);
Expand Down Expand Up @@ -47,9 +44,4 @@ namespace audiocontext {
method(javaObject_.get(), *make_jstring(waveType));

}

void OscillatorNode::connect(const AudioDestinationNode &destination) {
const auto method = javaClassLocal()->getMethod<void(AudioDestinationNode::javaobject)>("connect");
method(javaObject_.get(), destination.javaObject_.get());
}
} // namespace audiocontext
35 changes: 10 additions & 25 deletions android/src/main/cpp/OscillatorNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,31 @@
#include <react/jni/CxxModuleWrapper.h>
#include <react/jni/JMessageQueueThread.h>
#include <memory>
#include "AudioDestinationNode.h"
#include "AudioNode.h"

namespace audiocontext {

using namespace facebook;
using namespace facebook::jni;

class AudioDestinationNode;

class OscillatorNode : public jni::HybridClass<OscillatorNode> {
class OscillatorNode : public jni::HybridClass<OscillatorNode, AudioNode> {
public:
static auto constexpr kJavaDescriptor = "Lcom/audiocontext/nodes/oscillator/OscillatorNode;";

static jni::local_ref<OscillatorNode::jhybriddata> initHybrid(jni::alias_ref<jhybridobject> jThis)
{
return makeCxxInstance(jThis);
}

static void registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", OscillatorNode::initHybrid),
});
}

void start(double time);

void stop(double time);

double getFrequency();

double getDetune();

std::string getWaveType();
void setFrequency(double frequency);
void setDetune(double detune);
void setWaveType(const std::string& waveType);
void connect(const AudioDestinationNode &destination);

private:
friend HybridBase;
void setFrequency(double frequency);

global_ref<OscillatorNode::javaobject> javaObject_;
void setDetune(double detune);

explicit OscillatorNode(jni::alias_ref<OscillatorNode::jhybridobject>& jThis);
void setWaveType(const std::string &waveType);
};

} // namespace audiocontext
}// namespace audiocontext
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ package com.audiocontext.context
import com.audiocontext.nodes.AudioDestinationNode
import com.audiocontext.nodes.oscillator.OscillatorNode
import com.facebook.jni.HybridData
import com.facebook.react.bridge.ReactApplicationContext

// nodes

class AudioContext() : BaseAudioContext {
override val sampleRate: Int = 44100
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.audiocontext.nodes

import android.media.AudioTrack
import android.util.Log
import com.audiocontext.context.BaseAudioContext
import com.facebook.jni.HybridData
import com.facebook.react.bridge.ReactApplicationContext
Expand All @@ -10,20 +11,14 @@ class AudioDestinationNode(context: BaseAudioContext): AudioNode(context) {
override val numberOfInputs = 1
override val numberOfOutputs = 0

private val mHybridData: HybridData?;
private val mHybridData: HybridData? = initHybrid();

companion object {
init {
System.loadLibrary("react-native-audio-context")
}
}

init {
mHybridData = initHybrid()
}

external fun initHybrid(): HybridData?

override fun process(buffer: ShortArray, audioTrack: AudioTrack) {
audioTrack.write(buffer, 0, buffer.size)
}
Expand Down
20 changes: 18 additions & 2 deletions android/src/main/java/com/audiocontext/nodes/AudioNode.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
package com.audiocontext.nodes

import android.media.AudioTrack
import android.util.Log
import com.audiocontext.context.BaseAudioContext
import com.facebook.jni.HybridData


abstract class AudioNode(val context: BaseAudioContext) {
abstract val numberOfInputs: Int;
abstract val numberOfOutputs: Int;
private val connectedNodes = mutableListOf<AudioNode>()

fun connect(destination: AudioDestinationNode) {
private val mHybridData: HybridData?;

companion object {
init {
System.loadLibrary("react-native-audio-context")
}
}

init {
mHybridData = initHybrid()
}

external fun initHybrid(): HybridData?

fun connect(node: AudioNode) {
if(this.numberOfOutputs > 0) {
connectedNodes.add(destination)
connectedNodes.add(node)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.audiocontext.nodes.oscillator

import android.media.AudioAttributes
import android.media.AudioFormat
import android.media.AudioManager
import android.media.AudioTrack
Expand Down Expand Up @@ -33,7 +34,7 @@ class OscillatorNode(context: BaseAudioContext) : AudioScheduledSourceNode(conte
private var stopThread: Thread? = null
private var buffer: ShortArray = ShortArray(1024)

private val mHybridData: HybridData?;
private val mHybridData: HybridData? = initHybrid();

companion object {
init {
Expand All @@ -42,17 +43,23 @@ class OscillatorNode(context: BaseAudioContext) : AudioScheduledSourceNode(conte
}

init {
mHybridData = initHybrid()
val bufferSize = AudioTrack.getMinBufferSize(
context.sampleRate,
AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT)
this.audioTrack = AudioTrack(
AudioManager.STREAM_MUSIC, context.sampleRate, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM
)
}

external fun initHybrid(): HybridData?
val audioAttributes = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()

val audioFormat = AudioFormat.Builder()
.setSampleRate(context.sampleRate)
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
.build()

this.audioTrack = AudioTrack(audioAttributes, audioFormat, bufferSize, AudioTrack.MODE_STREAM, AudioManager.AUDIO_SESSION_ID_GENERATE)
}

fun getWaveType(): String {
return WaveType.toString(waveType)
Expand Down
4 changes: 3 additions & 1 deletion cpp/AudioContext/AudioContextHostObject.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#include <jsi/jsi.h>

#include <utility>
#include "AudioContextWrapper.h"
#include "OscillatorNodeHostObject.h"
#include "AudioDestinationNodeHostObject.h"
Expand All @@ -19,7 +21,7 @@ namespace audiocontext
public:
explicit AudioContextHostObject(std::shared_ptr<AudioContextWrapper> wrapper) : wrapper_(wrapper) {}

static void createAndInstallFromWrapper(std::shared_ptr<AudioContextWrapper> wrapper, jlong jsContext) {
static void createAndInstallFromWrapper(const std::shared_ptr<AudioContextWrapper>& wrapper, jlong jsContext) {
auto runtime = reinterpret_cast<jsi::Runtime *>(jsContext);
auto hostObject = std::make_shared<AudioContextHostObject>(wrapper);
auto object = jsi::Object::createFromHostObject(*runtime, hostObject);
Expand Down
1 change: 1 addition & 0 deletions cpp/AudioContext/AudioContextWrapper.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <memory>
#include <utility>
#include "OscillatorNodeWrapper.h"
#include "AudioDestinationNodeWrapper.h"

Expand Down
10 changes: 4 additions & 6 deletions cpp/AudioDestinationNode/AudioDestinationNodeHostObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@

#include <jsi/jsi.h>
#include "AudioDestinationNodeWrapper.h"
#include "OscillatorNodeWrapper.h"
#include "AudioNodeHostObject.h"

namespace audiocontext {
using namespace facebook;

class AudioDestinationNodeWrapper;
class OscillatorNodeWrapper;

class AudioDestinationNodeHostObject : public jsi::HostObject {

private:
friend class OscillatorNodeHostObject;
class AudioDestinationNodeHostObject : public AudioNodeHostObject {

protected:
std::shared_ptr<AudioDestinationNodeWrapper> wrapper_;

public:
explicit AudioDestinationNodeHostObject(std::shared_ptr<AudioDestinationNodeWrapper> wrapper): wrapper_(wrapper) {}
explicit AudioDestinationNodeHostObject(std::shared_ptr<AudioDestinationNodeWrapper> wrapper): AudioNodeHostObject(wrapper), wrapper_(wrapper) {}

jsi::Value get(jsi::Runtime& runtime, const jsi::PropNameID& name) override;
void set(jsi::Runtime& runtime, const jsi::PropNameID& name, const jsi::Value& value) override;
Expand Down
Loading