diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt index 329e3836..39f3a80d 100644 --- a/android/CMakeLists.txt +++ b/android/CMakeLists.txt @@ -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 @@ -27,8 +28,9 @@ add_library(react-native-audio-context SHARED src/main/cpp/OnLoad.cpp src/main/cpp/AudioContext src/main/cpp/OscillatorNode - src/main/cpp/AudioDestinationNode + src/main/cpp/AudioDestinationNode.h src/main/cpp/AudioNode + src/main/cpp/GainNode ../cpp/AudioContext/AudioContextHostObject ../cpp/AudioContext/AudioContextWrapper.h @@ -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) diff --git a/android/src/main/cpp/AudioContext.cpp b/android/src/main/cpp/AudioContext.cpp index ebe88894..a925a2d6 100644 --- a/android/src/main/cpp/AudioContext.cpp +++ b/android/src/main/cpp/AudioContext.cpp @@ -22,7 +22,7 @@ namespace audiocontext return std::shared_ptr(oscillatorCppInstance); } - std::shared_ptr AudioContext::getDestination() + std::shared_ptr AudioContext::getDestination() { static const auto method = javaClassLocal()->getMethod("getDestination"); auto destination = method(javaObject_.get()); @@ -31,4 +31,13 @@ namespace audiocontext return std::shared_ptr(destinationCppInstance); } + std::shared_ptr AudioContext::createGain() + { + static const auto method = javaClassLocal()->getMethod("createGain"); + auto gain = method(javaObject_.get()); + auto gainCppInstance = gain->cthis(); + + return std::shared_ptr(gainCppInstance); + } + } // namespace audiocontext diff --git a/android/src/main/cpp/AudioContext.h b/android/src/main/cpp/AudioContext.h index 00982fd8..358fdb69 100644 --- a/android/src/main/cpp/AudioContext.h +++ b/android/src/main/cpp/AudioContext.h @@ -6,9 +6,10 @@ #include #include #include "AudioContextHostObject.h" +#include "AudioContextWrapper.h" #include "OscillatorNode.h" #include "AudioDestinationNode.h" -#include "AudioContextWrapper.h" +#include "GainNode.h" namespace audiocontext { @@ -39,6 +40,7 @@ namespace audiocontext std::shared_ptr createOscillator(); std::shared_ptr getDestination(); + std::shared_ptr createGain(); void install(jlong jsContext); diff --git a/android/src/main/cpp/AudioDestinationNode.cpp b/android/src/main/cpp/AudioDestinationNode.cpp deleted file mode 100644 index cef18fb4..00000000 --- a/android/src/main/cpp/AudioDestinationNode.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "AudioDestinationNode.h" - -namespace audiocontext { - - using namespace facebook::jni; - -} // namespace audiocontext diff --git a/android/src/main/cpp/AudioDestinationNode.h b/android/src/main/cpp/AudioDestinationNode.h index b7526d53..155eaa65 100644 --- a/android/src/main/cpp/AudioDestinationNode.h +++ b/android/src/main/cpp/AudioDestinationNode.h @@ -4,15 +4,13 @@ #include #include #include -#include "OscillatorNode.h" +#include "AudioNode.h" namespace audiocontext { using namespace facebook; using namespace facebook::jni; - class OscillatorNode; - class AudioDestinationNode : public jni::HybridClass { public: static auto constexpr kJavaDescriptor = "Lcom/audiocontext/nodes/AudioDestinationNode;"; diff --git a/android/src/main/cpp/GainNode.cpp b/android/src/main/cpp/GainNode.cpp new file mode 100644 index 00000000..2534ee6e --- /dev/null +++ b/android/src/main/cpp/GainNode.cpp @@ -0,0 +1,16 @@ +#include "GainNode.h" + +namespace audiocontext{ + + using namespace facebook::jni; + + double GainNode::getGain(){ + static const auto method = javaClassLocal()->getMethod("getGain"); + return method(javaObject_.get()); + } + + void GainNode::setGain(double gain){ + static const auto method = javaClassLocal()->getMethod("setGain"); + method(javaObject_.get(), gain); + } +} diff --git a/android/src/main/cpp/GainNode.h b/android/src/main/cpp/GainNode.h new file mode 100644 index 00000000..cae8705d --- /dev/null +++ b/android/src/main/cpp/GainNode.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include +#include +#include "AudioNode.h" + +namespace audiocontext { + + using namespace facebook; + using namespace facebook::jni; + + class GainNode : public jni::HybridClass { + public: + static auto constexpr kJavaDescriptor = "Lcom/audiocontext/nodes/GainNode;"; + + double getGain(); + + void setGain(double gain); + }; + +} // namespace audiocontext diff --git a/android/src/main/java/com/audiocontext/context/AudioContext.kt b/android/src/main/java/com/audiocontext/context/AudioContext.kt index e966e21f..8f289e51 100644 --- a/android/src/main/java/com/audiocontext/context/AudioContext.kt +++ b/android/src/main/java/com/audiocontext/context/AudioContext.kt @@ -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 @@ -27,4 +28,8 @@ class AudioContext() : BaseAudioContext { override fun createOscillator(): OscillatorNode { return OscillatorNode(this) } + + override fun createGain(): GainNode { + return GainNode(this) + } } diff --git a/android/src/main/java/com/audiocontext/context/BaseAudioContext.kt b/android/src/main/java/com/audiocontext/context/BaseAudioContext.kt index eb5d124b..88d27e5d 100644 --- a/android/src/main/java/com/audiocontext/context/BaseAudioContext.kt +++ b/android/src/main/java/com/audiocontext/context/BaseAudioContext.kt @@ -1,6 +1,7 @@ package com.audiocontext.context import com.audiocontext.nodes.AudioDestinationNode +import com.audiocontext.nodes.GainNode import com.audiocontext.nodes.oscillator.OscillatorNode interface BaseAudioContext { @@ -8,4 +9,5 @@ interface BaseAudioContext { val destination: AudioDestinationNode abstract fun createOscillator(): OscillatorNode + abstract fun createGain(): GainNode } diff --git a/android/src/main/java/com/audiocontext/nodes/AudioDestinationNode.kt b/android/src/main/java/com/audiocontext/nodes/AudioDestinationNode.kt index e9da01a6..9562cbdc 100644 --- a/android/src/main/java/com/audiocontext/nodes/AudioDestinationNode.kt +++ b/android/src/main/java/com/audiocontext/nodes/AudioDestinationNode.kt @@ -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) { diff --git a/android/src/main/java/com/audiocontext/nodes/GainNode.kt b/android/src/main/java/com/audiocontext/nodes/GainNode.kt new file mode 100644 index 00000000..c8312d32 --- /dev/null +++ b/android/src/main/java/com/audiocontext/nodes/GainNode.kt @@ -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) + } +} diff --git a/cpp/AudioContext/AudioContextHostObject.cpp b/cpp/AudioContext/AudioContextHostObject.cpp index 8902b76a..d6f8550a 100644 --- a/cpp/AudioContext/AudioContextHostObject.cpp +++ b/cpp/AudioContext/AudioContextHostObject.cpp @@ -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!"); } diff --git a/cpp/AudioContext/AudioContextHostObject.h b/cpp/AudioContext/AudioContextHostObject.h index 897fce93..15f9d761 100644 --- a/cpp/AudioContext/AudioContextHostObject.h +++ b/cpp/AudioContext/AudioContextHostObject.h @@ -6,6 +6,7 @@ #include "AudioContextWrapper.h" #include "OscillatorNodeHostObject.h" #include "AudioDestinationNodeHostObject.h" +#include "GainNodeHostObject.h" namespace audiocontext { diff --git a/cpp/AudioContext/AudioContextWrapper.h b/cpp/AudioContext/AudioContextWrapper.h index 6c1a5254..97f0b53c 100644 --- a/cpp/AudioContext/AudioContextWrapper.h +++ b/cpp/AudioContext/AudioContextWrapper.h @@ -4,6 +4,7 @@ #include #include "OscillatorNodeWrapper.h" #include "AudioDestinationNodeWrapper.h" +#include "GainNodeWrapper.h" #ifdef ANDROID #include "AudioContext.h" @@ -30,11 +31,12 @@ namespace audiocontext { public: #ifdef ANDROID explicit AudioContextWrapper( - std::shared_ptr audiocontext) : audiocontext_(audiocontext) {} + const std::shared_ptr &audiocontext) : audiocontext_(audiocontext) {} #else explicit AudioContextWrapper() {} #endif std::shared_ptr createOscillator(); std::shared_ptr getDestination(); + std::shared_ptr createGain(); }; } // namespace audiocontext diff --git a/cpp/AudioContext/android/AudioContextWrapper.cpp b/cpp/AudioContext/android/AudioContextWrapper.cpp index 1fcd3bba..0932448e 100644 --- a/cpp/AudioContext/android/AudioContextWrapper.cpp +++ b/cpp/AudioContext/android/AudioContextWrapper.cpp @@ -12,5 +12,10 @@ namespace audiocontext { auto destination = audiocontext_->getDestination(); return std::make_shared(destination); } + + std::shared_ptr AudioContextWrapper::createGain() { + auto gain = audiocontext_->createGain(); + return std::make_shared(gain); + } } // namespace audiocontext #endif \ No newline at end of file diff --git a/cpp/AudioDestinationNode/AudioDestinationNodeHostObject.h b/cpp/AudioDestinationNode/AudioDestinationNodeHostObject.h index 1f56395a..aa0da347 100644 --- a/cpp/AudioDestinationNode/AudioDestinationNodeHostObject.h +++ b/cpp/AudioDestinationNode/AudioDestinationNodeHostObject.h @@ -8,7 +8,6 @@ namespace audiocontext { using namespace facebook; class AudioDestinationNodeWrapper; - class OscillatorNodeWrapper; class AudioDestinationNodeHostObject : public AudioNodeHostObject { @@ -16,13 +15,13 @@ namespace audiocontext { std::shared_ptr wrapper_; public: - explicit AudioDestinationNodeHostObject(std::shared_ptr wrapper): AudioNodeHostObject(wrapper), wrapper_(wrapper) {} + explicit AudioDestinationNodeHostObject(const std::shared_ptr &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 getPropertyNames(jsi::Runtime& rt) override; - static std::shared_ptr createFromWrapper(std::shared_ptr wrapper) { + static std::shared_ptr createFromWrapper(const std::shared_ptr &wrapper) { return std::make_shared(wrapper); } }; diff --git a/cpp/AudioDestinationNode/AudioDestinationNodeWrapper.h b/cpp/AudioDestinationNode/AudioDestinationNodeWrapper.h index 2ea67702..b8cd2871 100644 --- a/cpp/AudioDestinationNode/AudioDestinationNodeWrapper.h +++ b/cpp/AudioDestinationNode/AudioDestinationNodeWrapper.h @@ -4,7 +4,7 @@ #ifdef ANDROID #include "AudioDestinationNode.h" -#include "OscillatorNodeWrapper.h" +#include "AudioNodeWrapper.h" #endif #include "AudioNodeWrapper.h" @@ -18,15 +18,12 @@ namespace audiocontext { class AudioDestinationNodeWrapper: public AudioNodeWrapper { #ifdef ANDROID private: - friend class OscillatorNodeWrapper; - std::shared_ptr destination_; -#endif public: -#ifdef ANDROID - explicit AudioDestinationNodeWrapper(std::shared_ptr destination) : AudioNodeWrapper(destination), destination_(destination) {} + explicit AudioDestinationNodeWrapper(const std::shared_ptr &destination) : AudioNodeWrapper(destination), destination_(destination) {} #else + public: explicit AudioDestinationNodeWrapper() {} #endif }; diff --git a/cpp/AudioNode/AudioNodeHostObject.cpp b/cpp/AudioNode/AudioNodeHostObject.cpp new file mode 100644 index 00000000..3912ec8b --- /dev/null +++ b/cpp/AudioNode/AudioNodeHostObject.cpp @@ -0,0 +1,45 @@ +#include "AudioNodeHostObject.h" + +namespace audiocontext { + using namespace facebook; + + std::vector AudioNodeHostObject::getPropertyNames(jsi::Runtime& runtime) { + std::vector 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(rt); + wrapper_->connect(std::shared_ptr(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(rt); + wrapper_->disconnect(std::shared_ptr(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!"); + } + +} diff --git a/cpp/AudioNode/AudioNodeHostObject.h b/cpp/AudioNode/AudioNodeHostObject.h index ef3badef..23794309 100644 --- a/cpp/AudioNode/AudioNodeHostObject.h +++ b/cpp/AudioNode/AudioNodeHostObject.h @@ -10,10 +10,14 @@ namespace audiocontext { class AudioNodeHostObject : public jsi::HostObject { - public: + protected: std::shared_ptr wrapper_; public: - explicit AudioNodeHostObject(std::shared_ptr wrapper) : wrapper_(wrapper) {} + explicit AudioNodeHostObject(const std::shared_ptr &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 getPropertyNames(jsi::Runtime& rt) override; }; } // namespace audiocontext diff --git a/cpp/AudioNode/AudioNodeWrapper.h b/cpp/AudioNode/AudioNodeWrapper.h index 1e387d9a..4cbaaeec 100644 --- a/cpp/AudioNode/AudioNodeWrapper.h +++ b/cpp/AudioNode/AudioNodeWrapper.h @@ -8,15 +8,17 @@ namespace audiocontext { class AudioNodeWrapper { - public: #ifdef ANDROID + protected: std::shared_ptr node_; - - explicit AudioNodeWrapper(std::shared_ptr node) : node_(node) {} + public: + explicit AudioNodeWrapper(const std::shared_ptr &node) : node_(node) {} #else + public: explicit AudioNodeWrapper() {} #endif - void connect(const std::shared_ptr node) const; - void disconnect(const std::shared_ptr node) const; + public: + void connect(const std::shared_ptr &node) const; + void disconnect(const std::shared_ptr &node) const; }; } // namespace audiocontext diff --git a/cpp/AudioNode/android/AudioNodeWrapper.cpp b/cpp/AudioNode/android/AudioNodeWrapper.cpp index fb22b955..42aedf32 100644 --- a/cpp/AudioNode/android/AudioNodeWrapper.cpp +++ b/cpp/AudioNode/android/AudioNodeWrapper.cpp @@ -3,11 +3,11 @@ namespace audiocontext { - void AudioNodeWrapper::connect(const std::shared_ptr node) const { + void AudioNodeWrapper::connect(const std::shared_ptr &node) const { node_->connect(node->node_); } - void AudioNodeWrapper::disconnect(const std::shared_ptr node) const { + void AudioNodeWrapper::disconnect(const std::shared_ptr &node) const { node_->disconnect(node->node_); } } diff --git a/cpp/GainNode/GainNodeHostObject.cpp b/cpp/GainNode/GainNodeHostObject.cpp new file mode 100644 index 00000000..7b60e3e3 --- /dev/null +++ b/cpp/GainNode/GainNodeHostObject.cpp @@ -0,0 +1,40 @@ +#include "GainNodeHostObject.h" + +namespace audiocontext +{ + using namespace facebook; + + std::vector GainNodeHostObject::getPropertyNames(jsi::Runtime &runtime) + { + std::vector propertyNames = AudioNodeHostObject::getPropertyNames(runtime); + propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "gain")); + return propertyNames; + } + + jsi::Value GainNodeHostObject::get(jsi::Runtime &runtime, const jsi::PropNameID &propNameId) + { + auto propName = propNameId.utf8(runtime); + + if (propName == "gain") + { + auto gain = wrapper_->getGain(); + return jsi::Value(gain); + } + + return AudioNodeHostObject::get(runtime, propNameId); + } + + void GainNodeHostObject::set(jsi::Runtime &runtime, const jsi::PropNameID &propNameId, const jsi::Value &value) + { + auto propName = propNameId.utf8(runtime); + + if (propName == "gain") + { + double gain = value.getNumber(); + wrapper_->setGain(gain); + return; + } + + throw std::runtime_error("Not yet implemented!"); + } +} diff --git a/cpp/GainNode/GainNodeHostObject.h b/cpp/GainNode/GainNodeHostObject.h new file mode 100644 index 00000000..957a34d9 --- /dev/null +++ b/cpp/GainNode/GainNodeHostObject.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include "GainNodeWrapper.h" +#include "AudioNodeHostObject.h" + +namespace audiocontext { + using namespace facebook; + + class GainNodeWrapper; + + class GainNodeHostObject : public AudioNodeHostObject { + protected: + std::shared_ptr wrapper_; + + public: + explicit GainNodeHostObject(const std::shared_ptr &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 getPropertyNames(jsi::Runtime& rt) override; + + static std::shared_ptr createFromWrapper(const std::shared_ptr &wrapper) { + return std::make_shared(wrapper); + } + }; +} // namespace audiocontext diff --git a/cpp/GainNode/GainNodeWrapper.h b/cpp/GainNode/GainNodeWrapper.h new file mode 100644 index 00000000..94f0a774 --- /dev/null +++ b/cpp/GainNode/GainNodeWrapper.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include "AudioNodeWrapper.h" + +#ifdef ANDROID +#include "GainNode.h" +#endif + +namespace audiocontext { + using namespace facebook; + +#ifdef ANDROID + class GainNode; +#endif + + class GainNodeWrapper: public AudioNodeWrapper { +#ifdef ANDROID + private: + std::shared_ptr gain_; + public: + explicit GainNodeWrapper(const std::shared_ptr &gain) : AudioNodeWrapper( + gain), gain_(gain) {} +#else + public: + explicit GainNodeWrapper() {} +#endif + double getGain(); + void setGain(double gain); + }; +} // namespace audiocontext diff --git a/cpp/GainNode/android/GainNodeWrapper.cpp b/cpp/GainNode/android/GainNodeWrapper.cpp new file mode 100644 index 00000000..7e99b5e6 --- /dev/null +++ b/cpp/GainNode/android/GainNodeWrapper.cpp @@ -0,0 +1,12 @@ +#include "GainNodeWrapper.h" + +namespace audiocontext { + + double GainNodeWrapper::getGain() { + return gain_->getGain(); + } + + void GainNodeWrapper::setGain(double gain) { + gain_->setGain(gain); + } +} diff --git a/cpp/GainNode/ios/.keep b/cpp/GainNode/ios/.keep new file mode 100644 index 00000000..e69de29b diff --git a/cpp/OscillatorNode/OscillatorNodeHostObject.cpp b/cpp/OscillatorNode/OscillatorNodeHostObject.cpp index 2ae3619e..22cfad4f 100644 --- a/cpp/OscillatorNode/OscillatorNodeHostObject.cpp +++ b/cpp/OscillatorNode/OscillatorNodeHostObject.cpp @@ -6,13 +6,12 @@ namespace audiocontext std::vector OscillatorNodeHostObject::getPropertyNames(jsi::Runtime &runtime) { - std::vector propertyNames; + std::vector propertyNames = AudioNodeHostObject::getPropertyNames(runtime); propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "start")); propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "stop")); propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "frequency")); propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "detune")); propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "type")); - propertyNames.push_back(jsi::PropNameID::forAscii(runtime, "connect")); return propertyNames; } @@ -58,17 +57,7 @@ namespace audiocontext return jsi::String::createFromUtf8(runtime, waveType); } - 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(rt); - wrapper_->connect(std::shared_ptr(node)->wrapper_); - return jsi::Value::undefined(); - }); - } - - throw std::runtime_error("Prop not yet implemented!"); + return AudioNodeHostObject::get(runtime, propNameId); } void OscillatorNodeHostObject::set(jsi::Runtime &runtime, const jsi::PropNameID &propNameId, const jsi::Value &value) diff --git a/cpp/OscillatorNode/OscillatorNodeHostObject.h b/cpp/OscillatorNode/OscillatorNodeHostObject.h index c9fbb284..8640a984 100644 --- a/cpp/OscillatorNode/OscillatorNodeHostObject.h +++ b/cpp/OscillatorNode/OscillatorNodeHostObject.h @@ -14,13 +14,13 @@ namespace audiocontext { std::shared_ptr wrapper_; public: - explicit OscillatorNodeHostObject(std::shared_ptr wrapper) : AudioNodeHostObject(wrapper), wrapper_(wrapper) {} + explicit OscillatorNodeHostObject(const std::shared_ptr &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 getPropertyNames(jsi::Runtime& rt) override; - static std::shared_ptr createFromWrapper(std::shared_ptr wrapper) { + static std::shared_ptr createFromWrapper(const std::shared_ptr &wrapper) { return std::make_shared(wrapper); } }; diff --git a/cpp/OscillatorNode/OscillatorNodeWrapper.h b/cpp/OscillatorNode/OscillatorNodeWrapper.h index 7145e962..cf37e9d0 100644 --- a/cpp/OscillatorNode/OscillatorNodeWrapper.h +++ b/cpp/OscillatorNode/OscillatorNodeWrapper.h @@ -17,14 +17,9 @@ namespace audiocontext { class OscillatorNodeWrapper: public AudioNodeWrapper { #ifdef ANDROID std::shared_ptr oscillator_; -#else - std::shared_ptr oscillator_; -#endif - public: -#ifdef ANDROID - explicit OscillatorNodeWrapper( std::shared_ptr oscillator) : AudioNodeWrapper( - oscillator), oscillator_(oscillator) {} + explicit OscillatorNodeWrapper(const std::shared_ptr &oscillator) : AudioNodeWrapper( + oscillator), oscillator_(oscillator) {} #else explicit OscillatorNodeWrapper() : oscillator_(std::make_shared()) {} #endif @@ -33,7 +28,6 @@ namespace audiocontext { std::string getType(); void start(double time); void stop(double time); - void setFrequency(double frequency); void setDetune(double detune); void setType(const std::string& type); diff --git a/example/package.json b/example/package.json index 5d775135..8547404c 100644 --- a/example/package.json +++ b/example/package.json @@ -10,6 +10,7 @@ "build:ios": "react-native build-ios --scheme AudioContextExample --mode Debug --extra-params \"-sdk iphonesimulator CC=clang CPLUSPLUS=clang++ LD=clang LDPLUSPLUS=clang++ GCC_OPTIMIZATION_LEVEL=0 GCC_PRECOMPILE_PREFIX_HEADER=YES ASSETCATALOG_COMPILER_OPTIMIZATION=time DEBUG_INFORMATION_FORMAT=dwarf COMPILER_INDEX_STORE_ENABLE=NO\"" }, "dependencies": { + "@miblanchard/react-native-slider": "^2.6.0", "react": "18.2.0", "react-native": "0.74.3" }, diff --git a/example/src/App.tsx b/example/src/App.tsx index 3cd35435..cd16e67c 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,68 +1,156 @@ -import React from 'react'; +/* eslint-disable react/react-in-jsx-scope */ import { Button, Platform, StyleSheet, Text, View } from 'react-native'; -import { useRef, useEffect } from 'react'; +import { useRef, useState, useEffect } from 'react'; +import { Slider } from '@miblanchard/react-native-slider'; -import { AudioContext, type Oscillator } from 'react-native-audio-context'; +import { + AudioContext, + type Oscillator, + type Gain, +} from 'react-native-audio-context'; const App: React.FC = () => { + const [isPlaying, setIsPlaying] = useState(false); + const [gain, setGain] = useState(1.0); + const [frequency, setFrequency] = useState(440); + const [detune, setDetune] = useState(0); + const audioContextRef = useRef(null); const oscillatorRef = useRef(null); - const secondaryOscillatorRef = useRef(null); + const gainRef = useRef(null); - useEffect(() => { - if (!audioContextRef.current) { - audioContextRef.current = new AudioContext(); + const setUp = () => { + audioContextRef.current = new AudioContext(); + + oscillatorRef.current = audioContextRef.current.createOscillator(); + oscillatorRef.current.frequency = frequency; + oscillatorRef.current.detune = detune; + oscillatorRef.current.type = 'sine'; + + gainRef.current = audioContextRef.current.createGain(); + gainRef.current.gain = gain; + + if (Platform.OS === 'android') { + const destination = audioContextRef.current.destination; + oscillatorRef.current.connect(gainRef.current); + gainRef.current.connect(destination!); + } + }; - oscillatorRef.current = audioContextRef.current.createOscillator(); + const handleGainChange = (value: number[]) => { + const newValue = value[0] || 0.0; + setGain(newValue); + if (gainRef.current) { + gainRef.current.gain = newValue; + } + }; - secondaryOscillatorRef.current = - audioContextRef.current.createOscillator(); - secondaryOscillatorRef.current.frequency = 840; - secondaryOscillatorRef.current.type = 'square'; + const handleFrequencyChange = (value: number[]) => { + const newValue = value[0] || 440; + setFrequency(newValue); + if (oscillatorRef.current) { + oscillatorRef.current.frequency = newValue; + } + }; - // Destination is not implemented on IOS yet - if (Platform.OS === 'android') { - const destination = audioContextRef.current.destination; - oscillatorRef.current.connect(destination!); - secondaryOscillatorRef.current.connect(destination!); - } + const handleDetuneChange = (value: number[]) => { + const newValue = value[0] || 0; + setDetune(newValue); + if (oscillatorRef.current) { + oscillatorRef.current.detune = newValue; } + }; + useEffect(() => { return () => { - //TODO + oscillatorRef.current?.stop(0); }; }, []); - const startOscillator = () => { - oscillatorRef.current?.start(0); - secondaryOscillatorRef.current?.start(0); - }; - const stopOscillator = () => { - oscillatorRef.current?.stop(0); - secondaryOscillatorRef.current?.stop(0); + const handlePlayPause = () => { + if (!audioContextRef.current) { + setUp(); + } + + if (isPlaying) { + oscillatorRef.current?.stop(0); + } else { + oscillatorRef.current?.start(0); + } + + setIsPlaying(!isPlaying); }; return ( - + React Native Oscillator -