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/nodes properties implementation #52

Merged
merged 8 commits into from
Jul 30, 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
18 changes: 18 additions & 0 deletions android/src/main/cpp/AudioContext/AudioContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,22 @@ namespace audiocontext

return std::shared_ptr<StereoPannerNode>(stereoPannerCppInstance);
}

std::string AudioContext::getState()
{
static const auto method = javaClassLocal()->getMethod<JString()>("getState");
return method(javaObject_.get())->toStdString();
}

int AudioContext::getSampleRate()
{
static const auto method = javaClassLocal()->getMethod<jint()>("getSampleRate");
return method(javaObject_.get());
}

double AudioContext::getCurrentTime()
{
static const auto method = javaClassLocal()->getMethod<jdouble()>("getCurrentTime");
return method(javaObject_.get());
}
} // namespace audiocontext
4 changes: 3 additions & 1 deletion android/src/main/cpp/AudioContext/AudioContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ namespace audiocontext
std::shared_ptr<OscillatorNode> createOscillator();
std::shared_ptr<GainNode> createGain();
std::shared_ptr<StereoPannerNode> createStereoPanner();

std::string getState();
int getSampleRate();
double getCurrentTime();

void install(jlong jsContext);

Expand Down
10 changes: 10 additions & 0 deletions android/src/main/cpp/AudioNode/AudioNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ namespace audiocontext {

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

int AudioNode::getNumberOfInputs() {
static const auto method = javaClassLocal()->getMethod<int()>("getNumberOfInputs");
return method(javaObject_.get());
}

int AudioNode::getNumberOfOutputs() {
static const auto method = javaClassLocal()->getMethod<int()>("getNumberOfOutputs");
return method(javaObject_.get());
}

void AudioNode::connect(const std::shared_ptr<AudioNode> node) {
static const auto method = javaClassLocal()->getMethod<void(AudioNode::javaobject)>(
"connect");
Expand Down
2 changes: 2 additions & 0 deletions android/src/main/cpp/AudioNode/AudioNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ namespace audiocontext {
});
}

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

Expand Down
15 changes: 15 additions & 0 deletions android/src/main/cpp/AudioParam/AudioParam.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,19 @@ namespace audiocontext {
static const auto method = javaClassLocal()->getMethod<void(double)>("setValue");
method(javaObject_.get(), value);
}

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

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

double AudioParam::getMaxValue() {
static const auto method = javaClassLocal()->getMethod<double()>("getMaxValue");
return method(javaObject_.get());
}
}
3 changes: 3 additions & 0 deletions android/src/main/cpp/AudioParam/AudioParam.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ namespace audiocontext {

double getValue();
void setValue(double value);
double getDefaultValue();
double getMinValue();
double getMaxValue();

protected:
friend HybridBase;
Expand Down
5 changes: 0 additions & 5 deletions android/src/main/cpp/OscillatorNode/OscillatorNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,10 @@ namespace audiocontext {
static auto constexpr kJavaDescriptor = "Lcom/audiocontext/nodes/oscillator/OscillatorNode;";

void start(double time);

void stop(double time);

std::shared_ptr<AudioParam> getFrequencyParam();

std::shared_ptr<AudioParam> getDetuneParam();

std::string getWaveType();

void setWaveType(const std::string &waveType);
};
}// namespace audiocontext
13 changes: 13 additions & 0 deletions android/src/main/java/com/audiocontext/context/AudioContext.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.audiocontext.context

import android.os.SystemClock
import com.audiocontext.nodes.AudioDestinationNode
import com.audiocontext.nodes.GainNode
import com.audiocontext.nodes.StereoPannerNode
Expand All @@ -8,8 +9,11 @@ import com.facebook.jni.HybridData

class AudioContext() : BaseAudioContext {
override val sampleRate: Int = 44100
get() = field
override val destination: AudioDestinationNode = AudioDestinationNode(this)
get() = field
override var state = ContextState.RUNNING
private val contextStartTime: Long

private val mHybridData: HybridData?;

Expand All @@ -21,11 +25,20 @@ class AudioContext() : BaseAudioContext {

init {
mHybridData = initHybrid()
contextStartTime = SystemClock.elapsedRealtimeNanos()
}

external fun initHybrid(): HybridData?
external fun install(jsContext: Long)

fun getCurrentTime(): Double {
return (SystemClock.elapsedRealtimeNanos() - contextStartTime)/1_000_000_000.0
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return (SystemClock.elapsedRealtimeNanos() - contextStartTime)/1_000_000_000.0
return (SystemClock.elapsedRealtimeNanos() - contextStartTime) / 1_000_000_000.0

:)

}

fun getState(): String {
return ContextState.toString(state)
}

override fun createOscillator(): OscillatorNode {
return OscillatorNode(this)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.audiocontext.nodes.oscillator.OscillatorNode
interface BaseAudioContext {
val sampleRate: Int
val destination: AudioDestinationNode
var state: ContextState

abstract fun createOscillator(): OscillatorNode
abstract fun createGain(): GainNode
Expand Down
23 changes: 23 additions & 0 deletions android/src/main/java/com/audiocontext/context/ContextState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.audiocontext.context

enum class ContextState {
RUNNING,
CLOSED;

companion object {
fun fromString(state: String): ContextState {
return when (state.lowercase()) {
"running" -> RUNNING
"closed" -> CLOSED
else -> throw IllegalArgumentException("Unknown context state: $state")
}
}

fun toString(state: ContextState): String {
return when (state) {
RUNNING -> "running"
CLOSED -> "closed"
}
}
}
}
6 changes: 4 additions & 2 deletions android/src/main/java/com/audiocontext/nodes/AudioNode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import com.facebook.jni.HybridData


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

private val mHybridData: HybridData?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ package com.audiocontext.nodes.parameters

import com.facebook.jni.HybridData

class AudioParam(val defaultValue: Double, private val maxValue: Double, private val minValue: Double) {
class AudioParam(defaultValue: Double, maxValue: Double, minValue: Double) {
private var value: Double = defaultValue
private val defaultValue: Double = defaultValue
get() = field
private val maxValue: Double = maxValue
get() = field
private val minValue: Double = minValue
get() = field

private val mHybridData: HybridData?;

Expand Down
23 changes: 19 additions & 4 deletions cpp/AudioContext/AudioContextHostObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ namespace audiocontext {
std::vector<jsi::PropNameID> AudioContextHostObject::getPropertyNames(jsi::Runtime& runtime) {
std::vector<jsi::PropNameID> propertyNames;
propertyNames.push_back(jsi::PropNameID::forUtf8(runtime, "destination"));
propertyNames.push_back(jsi::PropNameID::forUtf8(runtime, "state"));
propertyNames.push_back(jsi::PropNameID::forUtf8(runtime, "sampleRate"));
propertyNames.push_back(jsi::PropNameID::forUtf8(runtime, "currentTime"));
propertyNames.push_back(jsi::PropNameID::forUtf8(runtime, "createOscillator"));
propertyNames.push_back(jsi::PropNameID::forUtf8(runtime, "createGain"));
propertyNames.push_back(jsi::PropNameID::forUtf8(runtime, "createStereoPanner"));
Expand All @@ -20,6 +23,22 @@ namespace audiocontext {
jsi::Value AudioContextHostObject::get(jsi::Runtime& runtime, const jsi::PropNameID& propNameId) {
auto propName = propNameId.utf8(runtime);

if(propName == "destination") {
return jsi::Object::createFromHostObject(runtime, destinationNode_);
}

if(propName == "state") {
return jsi::String::createFromUtf8(runtime, wrapper_->getState());
}

if(propName == "sampleRate") {
return jsi::Value(wrapper_->getSampleRate());
}

if(propName == "currentTime") {
return jsi::Value(wrapper_->getCurrentTime());
}

if(propName == "createOscillator") {
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 oscillator = wrapper_->createOscillator();
Expand All @@ -28,10 +47,6 @@ namespace audiocontext {
});
}

if(propName == "destination") {
return jsi::Object::createFromHostObject(runtime, destinationNode_);
}

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();
Expand Down
5 changes: 5 additions & 0 deletions cpp/AudioContext/AudioContextWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,15 @@ namespace audiocontext {
#endif
private:
std::shared_ptr<AudioDestinationNodeWrapper> destinationNode_;
std::string state_;
int sampleRate_;
public:
std::shared_ptr<OscillatorNodeWrapper> createOscillator();
std::shared_ptr<AudioDestinationNodeWrapper> getDestination();
std::shared_ptr<GainNodeWrapper> createGain();
std::shared_ptr<StereoPannerNodeWrapper> createStereoPanner();
std::string getState();
int getSampleRate();
double getCurrentTime();
};
} // namespace audiocontext
23 changes: 18 additions & 5 deletions cpp/AudioContext/android/AudioContextWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
namespace audiocontext {

AudioContextWrapper::AudioContextWrapper(const std::shared_ptr<AudioContext> &audiocontext) : audiocontext_(audiocontext) {
auto destinationNode = audiocontext_->getDestination();
destinationNode_ = std::make_shared<AudioDestinationNodeWrapper>(destinationNode);
auto destination = audiocontext_->getDestination();
destinationNode_ = std::make_shared<AudioDestinationNodeWrapper>(destination);
state_ = audiocontext_->getState();
sampleRate_ = audiocontext_->getSampleRate();
}

std::shared_ptr<OscillatorNodeWrapper> AudioContextWrapper::createOscillator() {
Expand All @@ -14,8 +16,7 @@ namespace audiocontext {
}

std::shared_ptr<AudioDestinationNodeWrapper> AudioContextWrapper::getDestination() {
auto destination = audiocontext_->getDestination();
return std::make_shared<AudioDestinationNodeWrapper>(destination);
return destinationNode_;
}

std::shared_ptr<GainNodeWrapper> AudioContextWrapper::createGain() {
Expand All @@ -27,5 +28,17 @@ namespace audiocontext {
auto panner = audiocontext_->createStereoPanner();
return std::make_shared<StereoPannerNodeWrapper>(panner);
}

std::string AudioContextWrapper::getState() {
return state_;
}

int AudioContextWrapper::getSampleRate() {
return sampleRate_;
}

double AudioContextWrapper::getCurrentTime() {
return audiocontext_->getCurrentTime();
}
} // namespace audiocontext
#endif
#endif
21 changes: 21 additions & 0 deletions cpp/AudioNode/AudioNodeHostObject.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "AudioNodeHostObject.h"
#include "AudioContextHostObject.h"

namespace audiocontext {
using namespace facebook;
Expand All @@ -7,6 +8,9 @@ namespace audiocontext {
std::vector<jsi::PropNameID> propertyNames;
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "connect"));
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "disconnect"));
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "numberOfInputs"));
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "numberOfOutputs"));
propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "context"));
return propertyNames;
}

Expand All @@ -33,6 +37,23 @@ namespace audiocontext {
});
}

if (propName == "numberOfInputs")
{
return jsi::Value(wrapper_->getNumberOfInputs());
}

if (propName == "numberOfOutputs")
{
return jsi::Value(wrapper_->getNumberOfOutputs());
}

if (propName == "context")
{
auto context = runtime.global().getPropertyAsObject(runtime, "__AudioContext");
auto hostObject = context.getHostObject<AudioContextHostObject>(runtime);
return jsi::Object::createFromHostObject(runtime, hostObject);
}

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

Expand Down
7 changes: 6 additions & 1 deletion cpp/AudioNode/AudioNodeWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@ namespace audiocontext {
protected:
std::shared_ptr<AudioNode> node_;
public:
explicit AudioNodeWrapper(const std::shared_ptr<AudioNode> &node) : node_(node) {}
explicit AudioNodeWrapper(const std::shared_ptr<AudioNode> &node);
#else
public:
explicit AudioNodeWrapper() {}
#endif
private:
int numberOfInputs_;
int numberOfOutputs_;
public:
int getNumberOfInputs() const;
int getNumberOfOutputs() const;
void connect(const std::shared_ptr<AudioNodeWrapper> &node) const;
void disconnect(const std::shared_ptr<AudioNodeWrapper> &node) const;
};
Expand Down
13 changes: 13 additions & 0 deletions cpp/AudioNode/android/AudioNodeWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@

namespace audiocontext {

AudioNodeWrapper::AudioNodeWrapper(const std::shared_ptr<AudioNode> &node) : node_(node) {
numberOfInputs_ = node->getNumberOfInputs();
numberOfOutputs_ = node->getNumberOfOutputs();
}

int AudioNodeWrapper::getNumberOfInputs() const {
return numberOfInputs_;
}

int AudioNodeWrapper::getNumberOfOutputs() const {
return numberOfOutputs_;
}

void AudioNodeWrapper::connect(const std::shared_ptr<AudioNodeWrapper> &node) const {
node_->connect(node->node_);
}
Expand Down
Loading