#include "audio-node.hpp"
#include "audio-context.hpp"
#include "audio-param.hpp"
IMPLEMENT_ES5_CLASS(AudioNode);
void AudioNode::init(Napi::Env env, Napi::Object exports) {
Napi::Function ctor = wrap(env);
JS_ASSIGN_SETTER(channelInterpretation);
JS_ASSIGN_SETTER(channelCountMode);
JS_ASSIGN_SETTER(channelCount);
JS_ASSIGN_METHOD(disconnect);
JS_ASSIGN_METHOD(connect);
JS_ASSIGN_GETTER(numberOfOutputs);
JS_ASSIGN_GETTER(numberOfInputs);
JS_ASSIGN_GETTER(context);
JS_ASSIGN_METHOD(destroy);
JS_ASSIGN_METHOD(diagnose);
exports.Set("AudioNode", ctor);
}
bool AudioNode::isAudioNode(Napi::Object obj) {
return obj.InstanceOf(_ctorEs5.Value());
}
inline std::string fromChannelCountMode(lab::ChannelCountMode mode) {
if (mode == lab::ChannelCountMode::ClampedMax) {
return "clamped-max";
} else if (mode == lab::ChannelCountMode::Explicit) {
return "explicit";
} else {
return "max";
}
}
inline lab::ChannelCountMode toChannelCountMode(const std::string &mode) {
if (mode == "clamped-max") {
return lab::ChannelCountMode::ClampedMax;
} else if (mode == "explicit") {
return lab::ChannelCountMode::Explicit;
} else {
return lab::ChannelCountMode::Max;
}
}
inline std::string fromChannelInterpretation(lab::ChannelInterpretation io) {
if (io == lab::ChannelInterpretation::Discrete) {
return "discrete";
} else {
return "speakers";
}
}
inline lab::ChannelInterpretation toChannelInterpretation(const std::string &io) {
if (io == "discrete") {
return lab::ChannelInterpretation::Discrete;
} else {
return lab::ChannelInterpretation::Speakers;
}
}
AudioNode::AudioNode(const Napi::CallbackInfo &info) : CommonNode(info.This(), "AudioNode") {
NAPI_ENV;
super(info);
Napi::Object context = info[0].As();
Napi::External extNode = info[1].As();
NodePtr *ext = reinterpret_cast(extNode.Data());
reset(context, *ext);
_channelCountMode = fromChannelCountMode(_impl->channelCountMode());
_channelInterpretation = fromChannelInterpretation(_impl->channelInterpretation());
}
AudioNode::~AudioNode() {
_destroy();
}
void AudioNode::_destroy() {
DES_CHECK;
CommonNode::_destroy();
}
// node2 node1.connect(node2);
// node2 node1.connect(node2, output);
// node2 node1.connect(node2, output, input);
// undefined node1.connect(param);
// undefined node1.connect(param, output);
JS_IMPLEMENT_METHOD(AudioNode, connect) {
THIS_CHECK;
REQ_OBJ_ARG(0, destination);
Napi::Object context = _context.Value();
AudioContext *audioContext = AudioContext::unwrap(context);
lab::AudioContext *ctx = audioContext->getCtx().get();
if (isAudioNode(destination)) {
LET_INT32_ARG(1, output);
LET_INT32_ARG(2, input);
AudioNode *destNode = AudioNode::unwrap(destination);
ctx->connect(destNode->_impl, _impl, input, output);
if (destNode->_impl.get() == static_cast(ctx->destinationNode().get())) {
ctx->synchronizeConnections();
}
} else if (AudioParam::isAudioParam(destination)) {
LET_INT32_ARG(1, output);
AudioParam *destParam = AudioParam::unwrap(destination);
ctx->connectParam(destParam->getParam(), _impl, output);
}
RET_UNDEFINED;
}
// undefined node1.disconnect();
// undefined node1.disconnect(dest);
// undefined node1.disconnect(dest, output);
// undefined node1.disconnect(dest, output, input);
// MAP TO --->
// ctx->disconnect(NodePtr destination, NodePtr source, int input, int output)
// ctx->disconnect(NodePtr source, int output)
JS_IMPLEMENT_METHOD(AudioNode, disconnect) {
THIS_CHECK;
int output = 0;
int input = 0;
Napi::Object destination;
Napi::Object context = _context.Value();
AudioContext *audioContext = AudioContext::unwrap(context);
lab::AudioContext *ctx = audioContext->getCtx().get();
if (info.Length() == 1) {
if (info[0].IsObject()) {
REQ_OBJ_ARG(0, destArg);
destination = destArg;
} else if (info[0].IsNumber()) {
REQ_INT_ARG(0, outputArg);
output = outputArg;
}
} else if (info.Length() == 2) {
REQ_OBJ_ARG(0, destArg);
REQ_INT_ARG(1, outputArg);
destination = destArg;
output = outputArg;
} else if (info.Length() == 3) {
REQ_OBJ_ARG(0, destArg);
REQ_INT_ARG(1, outputArg);
REQ_INT_ARG(2, inputArg);
destination = destArg;
output = outputArg;
input = inputArg;
} else {
// Disconnect self
ctx->disconnect(_impl, output);
RET_UNDEFINED;
}
if (AudioNode::isAudioNode(destination)) {
AudioNode *destNode = AudioNode::unwrap(destination);
ctx->disconnect(destNode->_impl, _impl, input, output);
} else if (AudioParam::isAudioParam(destination)) {
AudioParam *destParam = AudioParam::unwrap(destination);
ParamPtr param = destParam->getParam();
ctx->disconnectParam(param, _impl, output);
}
RET_UNDEFINED;
}
JS_IMPLEMENT_GETTER(AudioNode, context) {
THIS_CHECK;
RET_VALUE(_context.Value());
}
JS_IMPLEMENT_GETTER(AudioNode, numberOfInputs) {
THIS_CHECK;
RET_NUM(static_cast(_impl->numberOfInputs()));
}
JS_IMPLEMENT_GETTER(AudioNode, numberOfOutputs) {
THIS_CHECK;
RET_NUM(static_cast(_impl->numberOfOutputs()));
}
JS_IMPLEMENT_GETTER(AudioNode, channelCount) {
THIS_CHECK;
RET_NUM(static_cast(_impl->channelCount()));
}
JS_IMPLEMENT_SETTER(AudioNode, channelCount) {
THIS_CHECK;
SETTER_UINT32_ARG;
Napi::Object context = _context.Value();
AudioContext *audioContext = AudioContext::unwrap(context);
lab::ContextGraphLock graphLock(audioContext->getCtx().get(), "AudioNode::channelCountSetter");
_impl->setChannelCount(graphLock, v);
emit("channelCount", 1, &value);
RET_UNDEFINED;
}
JS_IMPLEMENT_GETTER(AudioNode, channelCountMode) {
THIS_CHECK;
RET_STR(_channelCountMode);
}
JS_IMPLEMENT_SETTER(AudioNode, channelCountMode) {
THIS_CHECK;
SETTER_STR_ARG;
CACHE_CAS(_channelCountMode, v);
// TODO: may be additional actions on change?
emit("channelCountMode", 1, &value);
RET_UNDEFINED;
}
JS_IMPLEMENT_GETTER(AudioNode, channelInterpretation) {
THIS_CHECK;
RET_STR(_channelInterpretation);
}
JS_IMPLEMENT_SETTER(AudioNode, channelInterpretation) {
THIS_CHECK;
SETTER_STR_ARG;
CACHE_CAS(_channelInterpretation, v);
// TODO: may be additional actions on change?
emit("channelInterpretation", 1, &value);
RET_UNDEFINED;
}
JS_IMPLEMENT_METHOD(AudioNode, destroy) {
THIS_CHECK;
emit("destroy");
_destroy();
RET_UNDEFINED;
}
JS_IMPLEMENT_METHOD(AudioNode, diagnose) {
THIS_CHECK;
Napi::Object context = _context.Value();
AudioContext *audioContext = AudioContext::unwrap(context);
lab::AudioContext *ctx = audioContext->getCtx().get();
ctx->diagnose(_impl);
RET_UNDEFINED;
}