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/analyser node #242

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#pragma once

#include <memory>
#include <string>
#include <vector>

#include "AnalyserNodeHostObject.h"
#include "AudioNodeHostObject.h"

namespace audioapi {
using namespace facebook;

class AnalyserNodeHostObject : public AudioNodeHostObject {
public:
explicit AnalyserNodeHostObject(const std::shared_ptr<AnalyserNode> &node)
: AudioNodeHostObject(node) {
addGetters(
JSI_EXPORT_PROPERTY_GETTER(AnalyserNodeHostObject, fftSize),
JSI_EXPORT_PROPERTY_GETTER(AnalyserNodeHostObject, frequencyBinCount),
JSI_EXPORT_PROPERTY_GETTER(AnalyserNodeHostObject, minDecibels),
JSI_EXPORT_PROPERTY_GETTER(AnalyserNodeHostObject, maxDecibels),
JSI_EXPORT_PROPERTY_GETTER(
AnalyserNodeHostObject, smoothingTimeConstant));
);

addFunctions(
JSI_EXPORT_FUNCTION(
AnalyserNodeHostObject, getFloatFrequencyData),
JSI_EXPORT_FUNCTION(
AnalyserNodeHostObject, getByteFrequencyData),
JSI_EXPORT_FUNCTION(
AnalyserNodeHostObject, getFloatTimeDomainData),
JSI_EXPORT_FUNCTION(
AnalyserNodeHostObject, getByteTimeDomainData));
);

addSetters(
JSI_EXPORT_PROPERTY_SETTER(AnalyserNodeHostObject, fftSize),
JSI_EXPORT_PROPERTY_SETTER(AnalyserNodeHostObject, minDecibels),
JSI_EXPORT_PROPERTY_SETTER(AnalyserNodeHostObject, maxDecibels),
JSI_EXPORT_PROPERTY_SETTER(
AnalyserNodeHostObject, smoothingTimeConstant));
);
}

JSI_PROPERTY_GETTER(fftSize) {
auto analyserNode = std::static_pointer_cast<AnalyserNode>(node_);
return {analyserNode->getFftSize()};
}

JSI_PROPERTY_GETTER(frequencyBinCount) {
auto analyserNode = std::static_pointer_cast<AnalyserNode>(node_);
return {analyserNode->getFrequencyBinCount()};
}

JSI_PROPERTY_GETTER(minDecibels) {
auto analyserNode = std::static_pointer_cast<AnalyserNode>(node_);
return {analyserNode->getMinDecibels()};
}

JSI_PROPERTY_GETTER(maxDecibels) {
auto analyserNode = std::static_pointer_cast<AnalyserNode>(node_);
return {analyserNode->getMaxDecibels()};
}

JSI_PROPERTY_GETTER(smoothingTimeConstant) {
auto analyserNode = std::static_pointer_cast<AnalyserNode>(node_);
return {analyserNode->getSmoothingTimeConstant()};
}

JSI_HOST_FUNCTION(getFloatFrequencyData) {
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION(getByteFrequencyData) {
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION(getFloatTimeDomainData) {
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION(getByteTimeDomainData) {
return jsi::Value::undefined();
}

JSI_PROPERTY_SETTER(fftSize) {
auto analyserNode = std::static_pointer_cast<AnalyserNode>(node_);
analyserNode->setFftSize(args[0].getNumber());
}

JSI_PROPERTY_SETTER(minDecibels) {
auto analyserNode = std::static_pointer_cast<AnalyserNode>(node_);
analyserNode->setMinDecibels(args[0].getNumber());
}

JSI_PROPERTY_SETTER(maxDecibels) {
auto analyserNode = std::static_pointer_cast<AnalyserNode>(node_);
analyserNode->setMaxDecibels(args[0].getNumber());
}

JSI_PROPERTY_SETTER(smoothingTimeConstant) {
auto analyserNode = std::static_pointer_cast<AnalyserNode>(node_);
analyserNode->setSmoothingTimeConstant(args[0].getNumber());
}
};
} // namespace audioapi
75 changes: 75 additions & 0 deletions packages/react-native-audio-api/common/cpp/core/AnalyserNode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include "AnalyserNode.h"
#include "AudioArray.h"
#include "AudioBus.h"
#include "BaseAudioContext.h"

namespace audioapi {
AnalyserNode::AnalyserNode(audioapi::BaseAudioContext *context)
: AudioNode(context) {
channelCount_ = 1;
fftSize_ = 2048;
minDecibels_ = -100;
maxDecibels_ = -30;
smoothingTimeConstant_ = 0.8;
inputBus_ =
std::make_unique<AudioBus>(context->getSampleRate(), MAX_FFT_SIZE * 2, 1);
}

int AnalyserNode::getFftSize() const {
return fftSize_;
}

int AnalyserNode::getFrequencyBinCount() const {
return fftSize_ / 2;
}

double AnalyserNode::getMinDecibels() const {
return minDecibels_;
}

double AnalyserNode::getMaxDecibels() const {
return maxDecibels_;
}

double AnalyserNode::getSmoothingTimeConstant() const {
return smoothingTimeConstant_;
}

void AnalyserNode::setFftSize(int fftSize) {
fftSize_ = fftSize;
}

void AnalyserNode::setMinDecibels(double minDecibels) {
minDecibels_ = minDecibels;
}

void AnalyserNode::setMaxDecibels(double maxDecibels) {
maxDecibels_ = maxDecibels;
}

void AnalyserNode::setSmoothingTimeConstant(double smoothingTimeConstant) {
smoothingTimeConstant_ = smoothingTimeConstant;
}

float *AnalyserNode::getFloatFrequencyData() {
return nullptr;
}

uint8_t *AnalyserNode::getByteFrequencyData() {
return nullptr;
}

float *AnalyserNode::getFloatTimeDomainData() {
return nullptr;
}

uint8_t *AnalyserNode::getByteTimeDomainData() {
return nullptr;
}

void AnalyserNode::processNode(
audioapi::AudioBus *processingBus,
int framesToProcess) {
// m_analyser.writeInput(inputBus, framesToProcess);
}
} // namespace audioapi
43 changes: 43 additions & 0 deletions packages/react-native-audio-api/common/cpp/core/AnalyserNode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#pragma once

#include <memory>

#include "AudioNode.h"

namespace audioapi {

class AudioBus;

class AnalyserNode : public AudioNode {
public:
explicit AnalyserNode(BaseAudioContext *context);

int getFftSize() const;
int getFrequencyBinCount() const;
double getMinDecibels() const;
double getMaxDecibels() const;

double getSmoothingTimeConstant() const;
void setFftSize(int fftSize);
void setMinDecibels(double minDecibels);
void setMaxDecibels(double maxDecibels);
void setSmoothingTimeConstant(double smoothingTimeConstant);

float *getFloatFrequencyData();
uint8_t *getByteFrequencyData();
float *getFloatTimeDomainData();
uint8_t *getByteTimeDomainData();

protected:
void processNode(AudioBus *processingBus, int framesToProcess) override;

private:
int fftSize_;
double minDecibels_;
double maxDecibels_;
double smoothingTimeConstant_;

std::unique_ptr<AudioBus> inputBus_;
};

} // namespace audioapi
6 changes: 3 additions & 3 deletions packages/react-native-audio-api/common/cpp/core/AudioNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ AudioBus *AudioNode::processAudio(AudioBus *outputBus, int framesToProcess) {
// - it has more than one output, so each output node can get the processed
// data without re-calculating the node.
bool canUseOutputBus =
outputBus != 0 && inputNodes_.size() < 2 && outputNodes_.size() < 2;
outputBus != nullptr && inputNodes_.size() < 2 && outputNodes_.size() < 2;

if (isAlreadyProcessed) {
// If it was already processed in the rendering quantum, return it.
Expand Down Expand Up @@ -214,15 +214,15 @@ void AudioNode::onInputDisconnected(AudioNode *node) {
inputNodes_.erase(position);
}

if (inputNodes_.size() > 0) {
if (!inputNodes_.empty()) {
return;
}

if (isEnabled()) {
node->onInputDisabled();
}

for (auto outputNode : outputNodes_) {
for (const auto &outputNode : outputNodes_) {
disconnectNode(outputNode);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ constexpr float MAX_FILTER_FREQUENCY = NYQUIST_FREQUENCY;
constexpr float MIN_FILTER_FREQUENCY = 0.0;
static float MAX_FILTER_GAIN = 40 * std::log10(MOST_POSITIVE_SINGLE_FLOAT);
constexpr float MIN_FILTER_GAIN = -MAX_GAIN;

constexpr int MAX_FFT_SIZE = 32768;
constexpr int MIN_FFT_SIZE = 32;
} // namespace audioapi
37 changes: 37 additions & 0 deletions packages/react-native-audio-api/src/core/AnalyserNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { IAnalyserNode } from '../interfaces';
import AudioNode from './AudioNode';
import BaseAudioContext from './BaseAudioContext';

export default class AnalyserNode extends AudioNode {
fftSize: number;
readonly frequencyBinCount: number;
minDecibels: number;
maxDecibels: number;
smoothingTimeConstant: number;

constructor(context: BaseAudioContext, analyser: IAnalyserNode) {
super(context, analyser);

this.fftSize = analyser.fftSize;
this.frequencyBinCount = analyser.frequencyBinCount;
this.minDecibels = analyser.minDecibels;
this.maxDecibels = analyser.maxDecibels;
this.smoothingTimeConstant = analyser.smoothingTimeConstant;
}

getFloatFrequencyData(array: number[]): void {
(this.node as IAnalyserNode).getFloatFrequencyData(array);
}

getByteFrequencyData(array: number[]): void {
(this.node as IAnalyserNode).getByteFrequencyData(array);
}

getFloatTimeDomainData(array: number[]): void {
(this.node as IAnalyserNode).getFloatTimeDomainData(array);
}

getByteTimeDomainData(array: number[]): void {
(this.node as IAnalyserNode).getByteTimeDomainData(array);
}
}
1 change: 1 addition & 0 deletions packages/react-native-audio-api/src/index.native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export { default as AudioBufferSourceNode } from './core/AudioBufferSourceNode';
export { default as AudioContext } from './core/AudioContext';
export { default as AudioDestinationNode } from './core/AudioDestinationNode';
export { default as AudioNode } from './core/AudioNode';
export { default as AnalyserNode } from './core/AnalyserNode';
export { default as AudioParam } from './core/AudioParam';
export { default as AudioScheduledSourceNode } from './core/AudioScheduledSourceNode';
export { default as BaseAudioContext } from './core/BaseAudioContext';
Expand Down
34 changes: 34 additions & 0 deletions packages/react-native-audio-api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,40 @@ export class AudioNode {
}
}

export class AnalyserNode extends AudioNode {
readonly fftSize: number;
readonly frequencyBinCount: number;
readonly minDecibels: number;
readonly maxDecibels: number;
readonly smoothingTimeConstant: number;

constructor(context: AudioContext, node: globalThis.AnalyserNode) {
super(context, node);

this.fftSize = node.fftSize;
this.frequencyBinCount = node.frequencyBinCount;
this.minDecibels = node.minDecibels;
this.maxDecibels = node.maxDecibels;
this.smoothingTimeConstant = node.smoothingTimeConstant;
}

public getByteFrequencyData(array: Uint8Array): void {
(this.node as globalThis.AnalyserNode).getByteFrequencyData(array);
}

public getByteTimeDomainData(array: Uint8Array): void {
(this.node as globalThis.AnalyserNode).getByteTimeDomainData(array);
}

public getFloatFrequencyData(array: Float32Array): void {
(this.node as globalThis.AnalyserNode).getFloatFrequencyData(array);
}

public getFloatTimeDomainData(array: Float32Array): void {
(this.node as globalThis.AnalyserNode).getFloatTimeDomainData(array);
}
}

export class AudioScheduledSourceNode extends AudioNode {
private hasBeenStarted: boolean = false;

Expand Down
13 changes: 13 additions & 0 deletions packages/react-native-audio-api/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,16 @@ export interface IAudioParam {
}

export interface IPeriodicWave {}

export interface IAnalyserNode extends IAudioNode {
fftSize: number;
readonly frequencyBinCount: number;
minDecibels: number;
maxDecibels: number;
smoothingTimeConstant: number;

getFloatFrequencyData: (array: number[]) => void;
getByteFrequencyData: (array: number[]) => void;
getFloatTimeDomainData: (array: number[]) => void;
getByteTimeDomainData: (array: number[]) => void;
}
Loading