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/gain node #39

Merged
merged 8 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
8 changes: 7 additions & 1 deletion android/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ include_directories(
../cpp/AudioDestinationNode
../cpp/OscillatorNode
../cpp/AudioNode
../cpp/GainNode
src/main/cpp
../node_modules/react-native/ReactCommon/jsi
../node_modules/react-native/ReactAndroid/src/main/jni/react/jni
Expand All @@ -29,6 +30,7 @@ add_library(react-native-audio-context SHARED
src/main/cpp/OscillatorNode
src/main/cpp/AudioDestinationNode
src/main/cpp/AudioNode
src/main/cpp/GainNode

../cpp/AudioContext/AudioContextHostObject
../cpp/AudioContext/AudioContextWrapper.h
Expand All @@ -42,9 +44,13 @@ add_library(react-native-audio-context SHARED
../cpp/OscillatorNode/OscillatorNodeWrapper.h
../cpp/OscillatorNode/android/OscillatorNodeWrapper.cpp

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

../cpp/GainNode/GainNodeHostObject
../cpp/GainNode/GainNodeWrapper.h
../cpp/GainNode/android/GainNodeWrapper.cpp
)

find_package(ReactAndroid REQUIRED CONFIG)
Expand Down
11 changes: 10 additions & 1 deletion android/src/main/cpp/AudioContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace audiocontext
return std::shared_ptr<OscillatorNode>(oscillatorCppInstance);
}

std::shared_ptr<AudioDestinationNode> AudioContext::getDestination()
std::shared_ptr<AudioDestinationNode> AudioContext::getDestination()
{
static const auto method = javaClassLocal()->getMethod<AudioDestinationNode()>("getDestination");
auto destination = method(javaObject_.get());
Expand All @@ -31,4 +31,13 @@ namespace audiocontext
return std::shared_ptr<AudioDestinationNode>(destinationCppInstance);
}

std::shared_ptr<GainNode> AudioContext::createGain()
{
static const auto method = javaClassLocal()->getMethod<GainNode()>("createGain");
auto gain = method(javaObject_.get());
auto gainCppInstance = gain->cthis();

return std::shared_ptr<GainNode>(gainCppInstance);
}

} // namespace audiocontext
4 changes: 3 additions & 1 deletion android/src/main/cpp/AudioContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
#include <react/jni/JMessageQueueThread.h>
#include <memory>
#include "AudioContextHostObject.h"
#include "AudioContextWrapper.h"
#include "OscillatorNode.h"
#include "AudioDestinationNode.h"
#include "AudioContextWrapper.h"
#include "GainNode.h"

namespace audiocontext
{
Expand Down Expand Up @@ -39,6 +40,7 @@ namespace audiocontext

std::shared_ptr<OscillatorNode> createOscillator();
std::shared_ptr<AudioDestinationNode> getDestination();
std::shared_ptr<GainNode> createGain();

void install(jlong jsContext);

Expand Down
6 changes: 0 additions & 6 deletions android/src/main/cpp/AudioDestinationNode.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1 @@
#include "AudioDestinationNode.h"

namespace audiocontext {

using namespace facebook::jni;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this file then? 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are right


} // namespace audiocontext
4 changes: 1 addition & 3 deletions android/src/main/cpp/AudioDestinationNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
#include <react/jni/CxxModuleWrapper.h>
#include <react/jni/JMessageQueueThread.h>
#include <memory>
#include "OscillatorNode.h"
#include "AudioNode.h"

namespace audiocontext {

using namespace facebook;
using namespace facebook::jni;

class OscillatorNode;

class AudioDestinationNode : public jni::HybridClass<AudioDestinationNode, AudioNode> {
public:
static auto constexpr kJavaDescriptor = "Lcom/audiocontext/nodes/AudioDestinationNode;";
Expand Down
16 changes: 16 additions & 0 deletions android/src/main/cpp/GainNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "GainNode.h"

namespace audiocontext{

using namespace facebook::jni;

double GainNode::getGain(){
static const auto method = javaClassLocal()->getMethod<jdouble()>("getGain");
return method(javaObject_.get());
}

void GainNode::setGain(double gain){
static const auto method = javaClassLocal()->getMethod<void(jdouble)>("setGain");
method(javaObject_.get(), gain);
}
}
23 changes: 23 additions & 0 deletions android/src/main/cpp/GainNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

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

namespace audiocontext {

using namespace facebook;
using namespace facebook::jni;

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

double getGain();

void setGain(double gain);
};

} // namespace audiocontext
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.audiocontext.context

import com.audiocontext.nodes.AudioDestinationNode
import com.audiocontext.nodes.GainNode
import com.audiocontext.nodes.oscillator.OscillatorNode
import com.facebook.jni.HybridData

Expand All @@ -27,4 +28,8 @@ class AudioContext() : BaseAudioContext {
override fun createOscillator(): OscillatorNode {
return OscillatorNode(this)
}

override fun createGain(): GainNode {
return GainNode(this)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.audiocontext.context

import com.audiocontext.nodes.AudioDestinationNode
import com.audiocontext.nodes.GainNode
import com.audiocontext.nodes.oscillator.OscillatorNode

interface BaseAudioContext {
val sampleRate: Int
val destination: AudioDestinationNode

abstract fun createOscillator(): OscillatorNode
abstract fun createGain(): GainNode
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
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


class AudioDestinationNode(context: BaseAudioContext): AudioNode(context) {
Expand Down
22 changes: 22 additions & 0 deletions android/src/main/java/com/audiocontext/nodes/GainNode.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.audiocontext.nodes

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

class GainNode(context: BaseAudioContext): AudioNode(context) {
override val numberOfInputs: Int = 1
override val numberOfOutputs: Int = 1
private var gain: Double = 1.0
get() = field
set(value) {
field = value
}

private val mHybridData: HybridData? = initHybrid();

override fun process(buffer: ShortArray, audioTrack: AudioTrack) {
audioTrack.setVolume(gain.toFloat())
super.process(buffer, audioTrack)
}
}
8 changes: 8 additions & 0 deletions cpp/AudioContext/AudioContextHostObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ namespace audiocontext {
return jsi::Object::createFromHostObject(runtime, destinationHostObject);
}

if(propName == "createGain") {
return jsi::Function::createFromHostFunction(runtime, propNameId, 0, [this](jsi::Runtime& runtime, const jsi::Value& thisValue, const jsi::Value* arguments, size_t count) -> jsi::Value {
auto gain = wrapper_->createGain();
auto gainHostObject = GainNodeHostObject::createFromWrapper(gain);
return jsi::Object::createFromHostObject(runtime, gainHostObject);
});
}

throw std::runtime_error("Not yet implemented!");
}

Expand Down
5 changes: 3 additions & 2 deletions cpp/AudioContext/AudioContextHostObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "AudioContextWrapper.h"
#include "OscillatorNodeHostObject.h"
#include "AudioDestinationNodeHostObject.h"
#include "GainNodeHostObject.h"

namespace audiocontext
{
Expand All @@ -19,9 +20,9 @@ namespace audiocontext
std::shared_ptr<AudioContextWrapper> wrapper_;

public:
explicit AudioContextHostObject(std::shared_ptr<AudioContextWrapper> wrapper) : wrapper_(wrapper) {}
explicit AudioContextHostObject(const std::shared_ptr<AudioContextWrapper> &wrapper) : wrapper_(wrapper) {}

static void createAndInstallFromWrapper(const 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
4 changes: 3 additions & 1 deletion cpp/AudioContext/AudioContextWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <utility>
#include "OscillatorNodeWrapper.h"
#include "AudioDestinationNodeWrapper.h"
#include "GainNodeWrapper.h"

#ifdef ANDROID
#include "AudioContext.h"
Expand All @@ -28,11 +29,12 @@ namespace audiocontext {
public:
#ifdef ANDROID
explicit AudioContextWrapper(
std::shared_ptr<AudioContext> audiocontext) : audiocontext_(audiocontext) {}
const std::shared_ptr<AudioContext> &audiocontext) : audiocontext_(audiocontext) {}
#else
explicit AudioContextWrapper() {}
#endif
std::shared_ptr<OscillatorNodeWrapper> createOscillator();
std::shared_ptr<AudioDestinationNodeWrapper> getDestination();
std::shared_ptr<GainNodeWrapper> createGain();
};
} // namespace audiocontext
5 changes: 5 additions & 0 deletions cpp/AudioContext/android/AudioContextWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,9 @@ namespace audiocontext {
auto destination = audiocontext_->getDestination();
return std::make_shared<AudioDestinationNodeWrapper>(destination);
}

std::shared_ptr<GainNodeWrapper> AudioContextWrapper::createGain() {
auto gain = audiocontext_->createGain();
return std::make_shared<GainNodeWrapper>(gain);
}
} // namespace audiocontext
5 changes: 2 additions & 3 deletions cpp/AudioDestinationNode/AudioDestinationNodeHostObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,20 @@ namespace audiocontext {
using namespace facebook;

class AudioDestinationNodeWrapper;
class OscillatorNodeWrapper;

class AudioDestinationNodeHostObject : public AudioNodeHostObject {

protected:
std::shared_ptr<AudioDestinationNodeWrapper> wrapper_;

public:
explicit AudioDestinationNodeHostObject(std::shared_ptr<AudioDestinationNodeWrapper> wrapper): AudioNodeHostObject(wrapper), wrapper_(wrapper) {}
explicit AudioDestinationNodeHostObject(const 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;
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& rt) override;

static std::shared_ptr<AudioDestinationNodeHostObject> createFromWrapper(std::shared_ptr<AudioDestinationNodeWrapper> wrapper) {
static std::shared_ptr<AudioDestinationNodeHostObject> createFromWrapper(const std::shared_ptr<AudioDestinationNodeWrapper> &wrapper) {
return std::make_shared<AudioDestinationNodeHostObject>(wrapper);
}
};
Expand Down
9 changes: 3 additions & 6 deletions cpp/AudioDestinationNode/AudioDestinationNodeWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#ifdef ANDROID
#include "AudioDestinationNode.h"
#include "OscillatorNodeWrapper.h"
#include "AudioNodeWrapper.h"
#endif

namespace audiocontext {
Expand All @@ -17,15 +17,12 @@ namespace audiocontext {
class AudioDestinationNodeWrapper: public AudioNodeWrapper {
#ifdef ANDROID
private:
friend class OscillatorNodeWrapper;

std::shared_ptr<AudioDestinationNode> destination_;
#endif

public:
#ifdef ANDROID
explicit AudioDestinationNodeWrapper(std::shared_ptr<AudioDestinationNode> destination) : AudioNodeWrapper(destination), destination_(destination) {}
explicit AudioDestinationNodeWrapper(const std::shared_ptr<AudioDestinationNode> &destination) : AudioNodeWrapper(destination), destination_(destination) {}
#else
public:
explicit AudioDestinationNodeWrapper() {}
#endif
};
Expand Down
45 changes: 45 additions & 0 deletions cpp/AudioNode/AudioNodeHostObject.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "AudioNodeHostObject.h"

namespace audiocontext {
using namespace facebook;

std::vector<jsi::PropNameID> AudioNodeHostObject::getPropertyNames(jsi::Runtime& runtime) {
std::vector<jsi::PropNameID> propertyNames;
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "connect"));
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "disconnect"));
return propertyNames;
}

jsi::Value AudioNodeHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propNameId) {
auto propName = propNameId.utf8(runtime);

if (propName == "connect")
{
return jsi::Function::createFromHostFunction(runtime, propNameId, 1, [this](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value
{
auto node = args[0].getObject(rt).getHostObject<AudioNodeHostObject>(rt);
wrapper_->connect(std::shared_ptr<AudioNodeHostObject>(node)->wrapper_);
return jsi::Value::undefined();
});
}

if (propName == "disconnect")
{
return jsi::Function::createFromHostFunction(runtime, propNameId, 1, [this](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value
{
auto node = args[0].getObject(rt).getHostObject<AudioNodeHostObject>(rt);
wrapper_->disconnect(std::shared_ptr<AudioNodeHostObject>(node)->wrapper_);
return jsi::Value::undefined();
});
}

throw std::runtime_error("Not yet implemented!");
}

void AudioNodeHostObject::set(jsi::Runtime& runtime, const jsi::PropNameID& propNameId, const jsi::Value& value) {
auto propName = propNameId.utf8(runtime);

throw std::runtime_error("Not yet implemented!");
}

}
8 changes: 6 additions & 2 deletions cpp/AudioNode/AudioNodeHostObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,14 @@ namespace audiocontext {

class AudioNodeHostObject : public jsi::HostObject {

public:
protected:
std::shared_ptr<AudioNodeWrapper> wrapper_;

public:
explicit AudioNodeHostObject(std::shared_ptr<AudioNodeWrapper> wrapper) : wrapper_(wrapper) {}
explicit AudioNodeHostObject(const std::shared_ptr<AudioNodeWrapper> &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;
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime& rt) override;
};
} // namespace audiocontext
Loading