Skip to content

feat: add composition project lane and session export workflow#916

Closed
ChuxiJ wants to merge 2 commits intocodex/v2-908-lora-comparefrom
codex/v2-909-composition
Closed

feat: add composition project lane and session export workflow#916
ChuxiJ wants to merge 2 commits intocodex/v2-908-lora-comparefrom
codex/v2-909-composition

Conversation

@ChuxiJ
Copy link
Contributor

@ChuxiJ ChuxiJ commented Mar 20, 2026

Summary

  • add a project/composition lane to the VST3 editor
  • persist project name, section plan, chord progression, and export notes
  • export a session summary file with result-slot metadata for DAW-safe handoff

Validation

  • cmake --build build/acestep_vst3 --config Release
  • copied the updated VST3 bundle to ~/Library/Audio/Plug-Ins/VST3/ACE-Step VST3 Shell.vst3

Closes #909
Refs #903

Summary by CodeRabbit

  • New Features

    • New composed UI: status strip, synth panel, transport, composition lane, result deck, and preview deck.
    • LoRA controls: load/unload, adapter selection, enable toggle and scaling.
    • Result compare slots and quick-cue compare preview.
    • Session export: save comprehensive session summary to a text file.
  • Improvements

    • Larger editor window with refreshed look-and-feel and unified chrome styling.
    • Improved state persistence for workflow, composition, LoRA and result metadata.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 20, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f9a1fe43-886b-4b7f-98a5-a87073f84a9c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Expanded ACEStep VST3 with a V2 UI: new themed look-and-feel, larger editor layout, modular components (StatusStrip, SynthPanel, TapeTransport, CompositionLane, ResultDeck, PreviewDeck), LoRA backend controls/requests, compare-slot workflow, session export, and extended persisted PluginState/result-take data.

Changes

Cohort / File(s) Summary
Editor & Wiring
plugins/acestep_vst3/src/PluginEditor.cpp, plugins/acestep_vst3/src/PluginEditor.h
Increased editor size, replaced manual painting with v2 chassis, installed V2LookAndFeel, swapped many flat controls for composed subcomponents, added file choosers and file-selection handlers, and wired new addAndMakeVisible layout stack (status → synth/transport → composition → results → preview).
UI Components
plugins/acestep_vst3/src/ CompositionLaneComponent.*, PreviewDeckComponent.*, ResultDeckComponent.*, StatusStripComponent.*, SynthPanelComponent.*, TapeTransportComponent.*, V2Chrome.*, V2LookAndFeel.*, corresponding .h files
Added multiple new JUCE components for V2 UI chrome and panels, their paint/resized implementations, accessors for controls (buttons, editors, selectors), and theme drawing helpers and custom look-and-feel rendering.
State & Model
plugins/acestep_vst3/src/PluginState.h, plugins/acestep_vst3/src/PluginState.cpp, plugins/acestep_vst3/src/PluginEnums.*, plugins/acestep_vst3/src/PluginConfig.h
Introduced PluginResultTake and PluginSessionState, extended PluginState with composition, LoRA, transport, workflow, compare and per-take fields; bumped state version; added TransportState and WorkflowMode enums and conversions.
Processor: LoRA, Compare, Export
plugins/acestep_vst3/src/PluginProcessor.cpp, plugins/acestep_vst3/src/PluginProcessor.h
Added LoRA request APIs and scheduling/apply hooks, compare-slot selection/cue/toggle methods, richer result-take population on generation completion, preview handling updates, and new exported exportSessionSummary(const juce::File&).
Backend Client
plugins/acestep_vst3/src/PluginBackendClient.cpp, plugins/acestep_vst3/src/PluginBackendClient.h
Added workflow-mode–aware generation payloads and new LoRA backend endpoints: getLoRAStatus, load/unload/toggle LoRA, setLoRAScale plus result structs and JSON parsing helpers.
Editor State & Preview Logic
plugins/acestep_vst3/src/PluginEditorState.cpp, plugins/acestep_vst3/src/PluginEditorPreview.cpp
Refactored state sync/persistence to composed panels, added many new text fields/sliders/selectors mapping to PluginState (reference/source paths, composition fields, LoRA settings, compare indices), and implemented choose/clear handlers plus session-export chooser that calls processor export.
Build
plugins/acestep_vst3/CMakeLists.txt
Added new component and V2 source files to the acestep_vst3 target.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Editor as Plugin Editor (UI)
    participant FileChooser as File Chooser
    participant Processor as Audio Processor
    participant FileSystem as File System

    User->>Editor: Click "Export Session"
    Editor->>FileChooser: Open save dialog (*.txt)
    FileChooser->>User: Show dialog
    User->>FileChooser: Confirm path
    FileChooser->>Editor: Return file
    Editor->>Editor: persistTextFields()
    Editor->>Processor: exportSessionSummary(file)
    Processor->>Processor: Gather PluginState & resultTakes
    Processor->>FileSystem: Overwrite/create file
    Processor->>FileSystem: Write session summary
    Processor-->>Editor: Return success
    Editor->>Editor: refreshStatusViews() (update export status)
    Editor->>User: Show export path/status
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related issues

  • Epic: Tape Synth V2 for ACE-Step VST3 #903 — Tape Synth V2 epic: This PR implements the V2 UI components, composition lane, transport, LoRA and compare flows described by the epic and directly realizes its objectives.

Poem

🐰 I hopped through panels, buttons, and code,
New decks and lanes where musical plans grow.
A session exported, chords snug in a file —
Tiny rabbit applause, a joyful UI smile. 🎶

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding a composition project lane and session export workflow to the VST3 editor.
Linked Issues check ✅ Passed The PR successfully implements core composition tools (#909 acceptance criteria): composition fields (project name, section plan, chord progression, export notes) are integrated into V2 plugin architecture via CompositionLaneComponent; session export is defined at plugin level via exportSessionSummary; LoRA support and compare workflows enhance the implementation; DAW-usability is maintained through modular component design.
Out of Scope Changes check ✅ Passed All significant changes directly support the composition and session export objectives: UI components (StatusStripComponent, SynthPanelComponent, TapeTransportComponent, CompositionLaneComponent, ResultDeckComponent, PreviewDeckComponent, V2LookAndFeel, V2Chrome) enable the composition workflow; backend client extensions support LoRA operations and session export; state extensions persist composition metadata and session context; processor methods expose session export and compare controls; enum/config updates support the new transport and workflow modes. No changes appear unrelated to the PR objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/v2-909-composition

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
plugins/acestep_vst3/src/PluginEditorPreview.cpp (1)

52-78: Consider guarding against concurrent FileChooser invocations.

If the user clicks the export button while the FileChooser dialog is already open, exportChooser_ is reassigned on line 59, which destroys the in-flight dialog. While this matches the existing pattern in choosePreviewFile(), consider disabling the button when a chooser is active or checking if (exportChooser_ != nullptr) return; at the start.

💡 Optional guard to prevent concurrent dialogs
 void ACEStepVST3AudioProcessorEditor::chooseSessionExportFile()
 {
+    if (exportChooser_ != nullptr)
+    {
+        return;
+    }
+
     const auto projectName = processor_.getState().projectName.trim();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/acestep_vst3/src/PluginEditorPreview.cpp` around lines 52 - 78,
chooseSessionExportFile currently reassigns exportChooser_ without guarding
against an existing active dialog; add an early guard in
ACEStepVST3AudioProcessorEditor::chooseSessionExportFile (e.g. if
(exportChooser_ != nullptr) return;) or disable the export button while
exportChooser_ is set so a concurrent invocation cannot replace the live
FileChooser, and keep the existing exportChooser_.reset() in the async callback
to allow reopening later; this mirrors the protection pattern used in
choosePreviewFile and prevents destroying an in-flight dialog.
plugins/acestep_vst3/src/PluginProcessor.cpp (1)

249-253: Consider checking write success after writeText.

The method assumes writeText succeeds after openedOk() returns true. While rare, disk-full or I/O errors during write could still occur. For robustness, consider checking output.failedToOpen() or the stream status after writing.

💡 Optional enhancement to check write status
     output.writeText(summary, false, false, "\n");
     output.flush();
+    if (output.getStatus().failed())
+    {
+        state_.errorMessage = "Failed to write session summary.";
+        return false;
+    }
     state_.lastExportPath = file.getFullPathName();
     state_.errorMessage = {};
     return true;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/acestep_vst3/src/PluginProcessor.cpp` around lines 249 - 253, After
writing the summary with FileOutputStream::writeText, check the stream status to
detect I/O errors (e.g., call output.failedToOpen() and/or check
output.getStatus().failed()) before treating the operation as successful; on
failure, set state_.errorMessage to an appropriate message, avoid updating
state_.lastExportPath, close/flush the stream, and return false from the
function (instead of proceeding to set state_.lastExportPath and returning
true). Ensure you reference the existing symbols writeText, flush, failedToOpen
/ getStatus, state_.lastExportPath, state_.errorMessage, and file when making
the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugins/acestep_vst3/src/PluginProcessor.cpp`:
- Around line 241-247: Remove the premature file.deleteFile() call and rely on
juce::FileOutputStream's default truncation behavior when creating the stream
for "file"; create juce::FileOutputStream output(file) without deleting first,
then check output.openedOk(), set state_.errorMessage = "Could not open the
export destination." and return false if it failed (the existing openedOk()
check and state_ usage should remain unchanged), ensuring no file is deleted
before confirming write capability.

---

Nitpick comments:
In `@plugins/acestep_vst3/src/PluginEditorPreview.cpp`:
- Around line 52-78: chooseSessionExportFile currently reassigns exportChooser_
without guarding against an existing active dialog; add an early guard in
ACEStepVST3AudioProcessorEditor::chooseSessionExportFile (e.g. if
(exportChooser_ != nullptr) return;) or disable the export button while
exportChooser_ is set so a concurrent invocation cannot replace the live
FileChooser, and keep the existing exportChooser_.reset() in the async callback
to allow reopening later; this mirrors the protection pattern used in
choosePreviewFile and prevents destroying an in-flight dialog.

In `@plugins/acestep_vst3/src/PluginProcessor.cpp`:
- Around line 249-253: After writing the summary with
FileOutputStream::writeText, check the stream status to detect I/O errors (e.g.,
call output.failedToOpen() and/or check output.getStatus().failed()) before
treating the operation as successful; on failure, set state_.errorMessage to an
appropriate message, avoid updating state_.lastExportPath, close/flush the
stream, and return false from the function (instead of proceeding to set
state_.lastExportPath and returning true). Ensure you reference the existing
symbols writeText, flush, failedToOpen / getStatus, state_.lastExportPath,
state_.errorMessage, and file when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 64eab96c-3019-4f67-b8be-e9b44e4f41fb

📥 Commits

Reviewing files that changed from the base of the PR and between 00f514a and 4733de4.

📒 Files selected for processing (8)
  • plugins/acestep_vst3/src/PluginEditor.cpp
  • plugins/acestep_vst3/src/PluginEditor.h
  • plugins/acestep_vst3/src/PluginEditorPreview.cpp
  • plugins/acestep_vst3/src/PluginEditorState.cpp
  • plugins/acestep_vst3/src/PluginProcessor.cpp
  • plugins/acestep_vst3/src/PluginProcessor.h
  • plugins/acestep_vst3/src/PluginState.cpp
  • plugins/acestep_vst3/src/PluginState.h

Comment on lines +241 to +247
file.deleteFile();
juce::FileOutputStream output(file);
if (!output.openedOk())
{
state_.errorMessage = "Could not open the export destination.";
return false;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid deleting the file before confirming write capability.

Calling file.deleteFile() before opening the output stream creates a window where the original file is lost but the new write may fail. JUCE's FileOutputStream already truncates existing content by default, making the explicit delete unnecessary and risky.

🛡️ Proposed fix to remove premature deletion
-    file.deleteFile();
     juce::FileOutputStream output(file);
     if (!output.openedOk())
     {
         state_.errorMessage = "Could not open the export destination.";
         return false;
     }
+    output.setPosition(0);
+    output.truncate();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/acestep_vst3/src/PluginProcessor.cpp` around lines 241 - 247, Remove
the premature file.deleteFile() call and rely on juce::FileOutputStream's
default truncation behavior when creating the stream for "file"; create
juce::FileOutputStream output(file) without deleting first, then check
output.openedOk(), set state_.errorMessage = "Could not open the export
destination." and return false if it failed (the existing openedOk() check and
state_ usage should remain unchanged), ensuring no file is deleted before
confirming write capability.

@ChuxiJ ChuxiJ force-pushed the codex/v2-909-composition branch from 4733de4 to cecb990 Compare March 20, 2026 18:42
@ChuxiJ ChuxiJ changed the base branch from main to codex/v2-908-lora-compare March 20, 2026 18:43
* fix: make the V2 VST3 editor vertically scrollable

* refine: polish the V2 tape-synth interface hierarchy
@ChuxiJ
Copy link
Contributor Author

ChuxiJ commented Mar 21, 2026

Superseded by consolidated V2 implementation PR #919, which now carries this stack forward against . Closing this split PR to keep the review surface clean.

@ChuxiJ ChuxiJ closed this Mar 21, 2026
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.

Tape Synth V2: Composition tools

1 participant