Skip to content

refactor(studio): extract the Web Audio engine to src/audio-graph.js (step 5)#20

Merged
byrongamatos merged 3 commits into
mainfrom
feat/es-module-split-audio-graph
Jul 8, 2026
Merged

refactor(studio): extract the Web Audio engine to src/audio-graph.js (step 5)#20
byrongamatos merged 3 commits into
mainfrom
feat/es-module-split-audio-graph

Conversation

@byrongamatos

@byrongamatos byrongamatos commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

What

Step 5 — the first entangled-core extraction. Moves the Web Audio playback engine out of main.js into src/audio-graph.js:

_getAudioCtx, _createReverbBus (internal), _play / _pause, _stopAllSources, _applyMixToLiveAudio / _applyAllMixToLive, _hasSoloActive (internal)

Breaking the cycle

audio ↔ animation ↔ waveform are mutually coupled: _play starts the per-frame playhead loop + master meter (_startAnimLoop/_stopAnimLoop/_startMasterMeter), which live with the animation/render layer in main.js. Rather than a static cycle (banned by the no-cycle gate), those 3 are injected via configureAudioGraph({...}) wired once at boot — so audio-graph.js is a clean lower layer that never imports back into main.js. Bodies moved verbatim except the 3 hook calls.

main.js 2711 → 2489.

Tests

node --test 11/11, pytest 25/25 (backend unaffected). Codex preflight: 0.

Behavioral (the playback engine) — on-device pass needed: play/pause/seek, mixer changes while playing, level meter, undo/redo (which re-applies the mix to live audio).

Summary by CodeRabbit

  • Refactor
    • Moved the Web Audio playback and mixing engine into a dedicated module.
    • Updated the app to connect playback controls, animation updates, and master metering through a shared configuration step.
    • Audio behavior remains the same for users, with no expected behavior change.
  • Documentation
    • Updated the changelog with an entry describing this ES-module migration step.

…(step 5)

Move the playback graph (_getAudioCtx, _createReverbBus, _play/_pause,
_stopAllSources, _applyMixToLiveAudio/_applyAllMixToLive, _hasSoloActive) out of
main.js. It's the lower audio layer: the per-frame playhead loop + master meter
it starts (_startAnimLoop/_stopAnimLoop/_startMasterMeter — animation/render
layer, still in main.js) are injected via configureAudioGraph({...}) at boot, so
audio-graph doesn't import back into main.js (no cycle). Bodies moved verbatim
except the 3 hook calls. _hasSoloActive kept internal. main.js 2711 -> 2489.

node 11/11, python 25/25.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 8, 2026 19:42
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d9cabf16-c90b-405e-8c6f-a8eab58dc288

📥 Commits

Reviewing files that changed from the base of the PR and between da0cf50 and fb6c539.

📒 Files selected for processing (1)
  • src/audio-graph.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/audio-graph.js

📝 Walkthrough

Walkthrough

The Web Audio playback engine is extracted from src/main.js into src/audio-graph.js, and main.js now wires UI callbacks into it with configureAudioGraph(...). The changelog records the move as behavior-preserving.

Changes

Audio graph extraction

Layer / File(s) Summary
Audio context and reverb bus setup
src/audio-graph.js
Lazily creates and reuses a shared AudioContext, then builds the convolver-based reverb bus and stores its node references.
Play/pause/stop playback graph
src/audio-graph.js
_play() builds the master and per-track audio graph, starts playback and UI hooks; _pause() stores pause offset and stops playback; _stopAllSources() clears live nodes and meter state.
Live mix application helpers
src/audio-graph.js
_hasSoloActive(), _applyMixToLiveAudio(), and _applyAllMixToLive() update live gain and pan while honoring solo state.
main.js wiring and cleanup
src/main.js, CHANGELOG.md
Imports playback and mix helpers from audio-graph.js, configures the injected UI callbacks, removes the old inline implementations, and documents the extraction in the changelog.

Estimated code review effort: 3 (Moderate) | ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: extracting the Web Audio engine into src/audio-graph.js as step 5.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/es-module-split-audio-graph

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR continues the ES-module migration by extracting the Web Audio playback engine from src/main.js into a new lower-level module src/audio-graph.js, using configureAudioGraph({...}) to inject animation/meter hooks and avoid an import cycle back into main.js.

Changes:

  • Moved Web Audio engine functions (_getAudioCtx, _play/_pause, _stopAllSources, live mix application helpers) from main.js into new src/audio-graph.js.
  • Added configureAudioGraph({...}) boot-time wiring in main.js to inject animation loop + master meter seams into the audio layer.
  • Documented the refactor step in CHANGELOG.md.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
src/main.js Imports audio engine functions from audio-graph.js and wires injected hooks via configureAudioGraph.
src/audio-graph.js New module containing the extracted Web Audio playback engine and injection seam.
CHANGELOG.md Notes migration step 5 and the cycle-breaking injection approach.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/audio-graph.js Outdated
Comment thread src/audio-graph.js
Comment thread src/audio-graph.js
Comment thread src/audio-graph.js
Comment thread src/audio-graph.js Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/audio-graph.js`:
- Around line 222-229: The original-track branch in _applyMixToLiveAudio can
throw when S.mixState.original is missing, unlike _play() and
_applyAllMixToLive() which already handle that fallback. Update the trackKey ===
'original' path to use the same safe original-track mix state lookup and guard
against an uninitialized S.mixState.original before reading st.muted, st.solo,
st.volume, or st.pan so live updates for original do not fail.
- Around line 172-180: The reverb send in audio-graph.js is currently tapped
from eqHigh before the main gain stage, so tracks that are muted, soloed out, or
faded can still feed the wet path. Update the reverb-send routing in the audio
graph setup to source from gain instead of eqHigh, or otherwise apply the same
effective mute/solo/fade gain to the send, keeping the existing reverbNode
connection behavior intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5748d2f9-bab9-4f9a-bd22-7a45bc4a4881

📥 Commits

Reviewing files that changed from the base of the PR and between 13b4036 and da0cf50.

📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/audio-graph.js
  • src/main.js

Comment thread src/audio-graph.js
Comment thread src/audio-graph.js
byrongamatos and others added 2 commits July 8, 2026 21:49
… deferred

Address review on #20:
- configureAudioGraph(h={}) with typeof-function guards (safe no-arg / bad-value).
- ctx.resume(): swallow the promise rejection (autoplay/gesture blocks) instead
  of leaving it unhandled.
- add tests/audio-graph.test.mjs (export surface, configure-seam wiring via
  _pause -> injected stopAnimLoop, no-arg tolerance).

node 14/14, python 25/25.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address CodeRabbit minor on #20 — match the sibling track branch's defensive
default so a live 'original' update can't throw if mixState.original is ever
absent. (Container always inits it; consistency + belt-and-suspenders.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@byrongamatos
byrongamatos merged commit 4d2f39e into main Jul 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants