Skip to content

feat: Graph refactor chapter II#991

Open
poneciak57 wants to merge 59 commits into
mainfrom
feat/graph_refactor_2
Open

feat: Graph refactor chapter II#991
poneciak57 wants to merge 59 commits into
mainfrom
feat/graph_refactor_2

Conversation

@poneciak57
Copy link
Copy Markdown
Contributor

@poneciak57 poneciak57 commented Mar 19, 2026

Closes RNAA-433

⚠️ Breaking changes ⚠️

Introduced changes

Checklist

  • Linked relevant issue
  • Updated relevant documentation
  • Added/Conducted relevant tests
  • Performed self-review of the code
  • Updated Web Audio API coverage
  • Added support for web
  • Updated old arch android spec file

@maciejmakowski2003 maciejmakowski2003 force-pushed the feat/graph_refactor_2 branch 2 times, most recently from 62ae703 to 71f1fd0 Compare March 31, 2026 06:37
@mdydek mdydek marked this pull request as ready for review May 7, 2026 09:34
@mdydek mdydek added the feature New feature label May 7, 2026
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

just checking in
is it possible to call start and stop concurently (eg at the same time)?

Copy link
Copy Markdown
Contributor Author

@poneciak57 poneciak57 left a comment

Choose a reason for hiding this comment

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

Overally it looks really great. One global issue is lack of high level documentation. It would be great to write/generate some high level design doc on top of that or keep existing ones in sync with the code

But as i said overally good job 👍

Comment on lines +35 to +36
delay_ring::bufferOperation(
delayBuffer, audioBuffer_, framesToProcess, writeIndex, delay_ring::BufferAction::WRITE);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

why u have Action type instead of having two methods write/read?

@@ -26,7 +24,7 @@ ConvolverNode::ConvolverNode(
void ConvolverNode::setBuffer(
const std::shared_ptr<AudioBuffer> &buffer,
std::vector<std::unique_ptr<Convolver>> convolvers,
const std::shared_ptr<ThreadPool> &threadPool,
const std::shared_ptr<ThreadPool<32>> &threadPool,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

32 is deffinitly too much
threads are used here for compute heavy operations so should be determined by hardware_concurrency. Otherwise they will hog cpu and steal power from each other.
Usually it does not matter that much but here they are not sleeping theyre job is to compute

Comment on lines +103 to +106
if (framesToProcess != RENDER_QUANTUM_SIZE) {
printf(
"[AUDIOAPI WARN] convolver requires 128 buffer size for each render quantum, otherwise quality of convolution is very poor\n");
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

printf does not show in android logcat use if macro based on system

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

make sure this file is compiled with -O3 -ffast-math

Comment on lines +70 to +78
/// Envelope threshold at which the impulse response is considered inaudible (-80 dB).
static constexpr double kTailEpsilon = 1e-4;

/// Hard upper bound on the computed tail length (seconds).
static constexpr float kMaxTailSeconds = 30.0f;

/// Keeps `log(r)` bounded away from zero when the pole sits on or outside
/// the unit circle.
static constexpr double kPoleRadiusEpsilon = 1e-5;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

constexpr does not need to be marked static

@@ -108,7 +108,7 @@ class PromiseVendor {
private:
jsi::Runtime *runtime_;
std::shared_ptr<react::CallInvoker> callInvoker_;
std::shared_ptr<ThreadPool> threadPool_;
std::shared_ptr<ThreadPool<96>> threadPool_;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

96?

Comment on lines +38 to +65
auto drainA = [&] {
AGEvent ev;
while (eventReceiver_.try_receive(ev) == ResponseStatus::SUCCESS) {
if (ev) {
ev(audioGraph, *disposer_);
}
}
};

// Steady-state: drain any A events queued since the last cycle.
drainA();

// For every pending orphan on Channel B: ensure Channel A's receive
// cursor has reached the barrier the GC thread snapshotted at orphan
// enqueue time. Until that barrier is met, every A event that the
// orphan happens-after must still be in flight; we drain A again to
// catch up. Only then do we consume and apply the orphan.
while (const OrphanEnvelope *front = gcEventReceiver_.try_peek()) {
if (eventReceiver_.rcvCursor() < front->barrier) {
drainA();
if (eventReceiver_.rcvCursor() < front->barrier) {
// Producer is mid-send on Channel A; the event will arrive
// imminently. Defer this orphan to the next processEvents()
// tick rather than burning audio-thread cycles spinning.
break;
}
}
OrphanEnvelope consumed;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this "vector-clock-like" aproach is great, but the logic seems to be split between few places. It would be nice to maybe make some wrapper on top of the SPSC to handle that scenario

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants