Skip to content

Commit fa8d7d9

Browse files
Ecursoragent
authored andcommitted
Cover mode fixes, queue reset on startup, Simple/Custom shared fields, run_local.sh, UI cleanup
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent d080071 commit fa8d7d9

12 files changed

Lines changed: 749 additions & 165 deletions

README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
# <img height="250" alt="image" src="https://github.com/user-attachments/assets/000f485b-3bb1-48c4-8031-cd941eec6bf7" />
1+
<img height="250" alt="image" src="https://github.com/user-attachments/assets/000f485b-3bb1-48c4-8031-cd941eec6bf7" />
2+
3+
# AceForge
24

35
AceForge is a **local-first AI music workstation for macOS Silicon** powered by **[ACE-Step](https://github.com/ace-step/ACE-Step)**<br>
46

@@ -59,6 +61,24 @@ AceForge is a **local-first AI music workstation for macOS Silicon** powered by
5961

6062
> **Note:** The app bundle does NOT include the large model files. On first run, it will download the ACE-Step models (several GB) automatically. You can monitor the download progress in the Terminal window or in the Server Console panel in the web interface.
6163
64+
### Option 2: Run locally for testing (developers)
65+
66+
To run the app from source without building the `.app` bundle:
67+
68+
1. **One-time setup:** Install dependencies (e.g. run the full build once to create the venv):
69+
```bash
70+
./build_local.sh
71+
```
72+
This creates `venv_build/` and installs Python deps. You can cancel after the PyInstaller step if you only want to run locally.
73+
74+
2. **Run the server:**
75+
```bash
76+
./run_local.sh
77+
```
78+
This builds the React UI if needed (requires [Bun](https://bun.sh)), then starts the Flask server at **http://127.0.0.1:5056**. Open that URL in your browser to use AceForge.
79+
80+
If you prefer to use your own venv instead of `venv_build`, install deps with `pip install -r requirements_ace_macos.txt` (and the same extra steps as in `build_local.sh` for TTS/ACE-Step), then run `python music_forge_ui.py`.
81+
6282
## Using AceForge (high-level workflow)
6383

6484
1. Launch AceForge and wait for the UI

api/generate.py

Lines changed: 154 additions & 46 deletions
Large diffs are not rendered by default.

cdmf_pipeline_ace_step.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,7 +1232,7 @@ def text2music_diffusion_process(
12321232
use_erg_lyric=False,
12331233
use_erg_diffusion=False,
12341234
retake_random_generators=None,
1235-
retake_variance=0.5,
1235+
retake_variance=0.2,
12361236
add_retake_noise=False,
12371237
guidance_scale_text=0.0,
12381238
guidance_scale_lyric=0.0,
@@ -1929,7 +1929,7 @@ def __call__(
19291929
lora_name_or_path: str = "none",
19301930
lora_weight: float = 1.0,
19311931
retake_seeds: list = None,
1932-
retake_variance: float = 0.5,
1932+
retake_variance: float = 0.2, # ACE-Step-MCP retake/repaint default
19331933
task: str = "text2music",
19341934
repaint_start: int = 0,
19351935
repaint_end: int = 0,

docs/ACE-Step-INFERENCE.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
Source: https://github.com/ace-step/ACE-Step-1.5/blob/main/docs/en/INFERENCE.md
44
Use for: GenerationParams/GenerationConfig, task types (text2music, cover, repaint, etc.),
55
reference_audio vs src_audio, audio_cover_strength, and parameter specs.
6+
7+
AceForge alignment: We align core defaults with the working ACE-Step-MCP reference
8+
(https://huggingface.co/spaces/reach-vb/ACE-Step-MCP/blob/main/ui/components.py):
9+
ref_audio_strength=0.5 (Audio2Audio/cover reference), retake_variance=0.2 (retake/repaint),
10+
and pipeline param names ref_audio_input, src_audio_path, audio2audio_enable.
611
-->
712

813
# ACE-Step Inference API Documentation

docs/ACEFORGE_API.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,15 +121,17 @@ ACE-Step text-to-music (and related tasks). Jobs are queued and run one at a tim
121121
- `songDescription` or `style`: text prompt (caption).
122122
- `lyrics`: optional lyrics (or "[inst]" for instrumental).
123123
- `instrumental`: boolean (default true).
124-
- `duration`: seconds (15–240), or -1/0 for auto-detection (pipeline will randomly select 30–240s).
124+
- `duration`: seconds (15–240).
125125
- `inferenceSteps`: int (e.g. 55).
126126
- `guidanceScale`: float (e.g. 6.0).
127127
- `seed`: int; if `randomSeed` is true, server may override with random.
128-
- `taskType`: `"text2music"` | `"retake"` | `"repaint"` | `"extend"` | `"cover"` | `"audio2audio"` | `"lego"` | `"extract"` | `"complete"`. **Lego**, **extract**, and **complete** require the ACE-Step **Base** DiT model (see Preferences and ACE-Step models).
129-
- `instruction`: optional; for `taskType` **lego** (and extract/complete), task-specific instruction (e.g. `"Generate the guitar track based on the audio context:"`). If omitted for lego, the server builds one from track name/caption.
130-
- `referenceAudioUrl`, `sourceAudioUrl`: URLs like `/audio/refs/...` or `/audio/<filename>` for reference/cover. For **lego**, **extract**, and **complete**, **sourceAudioUrl** is the backing/source audio (required).
131-
- `audioCoverStrength` / `ref_audio_strength`: 0–1.
132-
- `repaintingStart`, `repaintingEnd`: for repaint task.
128+
- **Task and audio params** (see [ACE-Step Tutorial](https://github.com/ace-step/ACE-Step-1.5/blob/main/docs/en/Tutorial.md#guiding-the-elephant-what-can-you-control)): The API accepts both **ACE-Step official names** (snake_case) and **UI names** (camelCase): `task_type` or `taskType`; `reference_audio` or `referenceAudioUrl` or `reference_audio_path`; `src_audio` or `sourceAudioUrl` or `source_audio_path`; `audio_cover_strength` or `audioCoverStrength` or `ref_audio_strength`.
129+
- `taskType` / `task_type`: `"text2music"` | `"retake"` | `"repaint"` | `"extend"` | `"cover"` | `"audio2audio"` | `"lego"` | `"extract"` | `"complete"`. **Lego**, **extract**, and **complete** require the ACE-Step **Base** DiT model (see Preferences and ACE-Step models).
130+
- `instruction`: optional; for **lego** (and extract/complete), task-specific instruction (e.g. `"Generate the guitar track based on the audio context:"`). If omitted for lego, the server builds one from track name/caption.
131+
- `reference_audio` / `referenceAudioUrl`: path or URL for reference audio (style/timbre). `src_audio` / `sourceAudioUrl`: path or URL for source/backing audio (cover, repaint, lego, etc.). For **lego**, **extract**, and **complete**, source audio is required.
132+
- `audio_cover_strength` / `audioCoverStrength`: 0–1 (reference/source influence strength). Defaults: **cover/retake** 0.8 (strong source); **audio2audio** 0.5 (matches [ACE-Step-MCP](https://huggingface.co/spaces/reach-vb/ACE-Step-MCP)); **lego** uses `legoBackingInfluence` (default 0.25).
133+
- `retake_variance` / `retakeVariance`: 0–1, default 0.2 (retake/repaint; aligned with ACE-Step-MCP).
134+
- `repaintingStart`, `repaintingEnd` / `repaint_start`, `repaint_end`: for repaint task; -1 end = end of audio.
133135
- `title`: base name for output file.
134136
- `outputDir` / `output_dir`: optional; else uses app default.
135137
- `keyScale`, `timeSignature`, `vocalLanguage`, `bpm`: optional.

generate_ace.py

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -567,9 +567,9 @@ def _prepare_reference_audio(
567567
src_audio_path: str | None,
568568
) -> tuple[str, bool, Optional[str]]:
569569
"""
570-
Normalise the ACE-Step edit / audio2audio mode:
570+
Normalise the ACE-Step edit / audio2audio mode (task_type, reference_audio, src_audio per Tutorial/INFERENCE):
571571
572-
- Task is clamped to one of: text2music / retake / repaint / extend.
572+
- Task (task_type) is clamped to one of: text2music / retake / repaint / extend.
573573
- UI tasks "cover" and "audio2audio" are mapped to "retake" (ACE-Step
574574
then uses ref_audio_input and sets task to "audio2audio" internally).
575575
- If Audio2Audio is enabled while task is still 'text2music', we
@@ -830,11 +830,11 @@ def _run_ace_text2music(
830830
task: str = "text2music",
831831
repaint_start: float = 0.0,
832832
repaint_end: float = 0.0,
833-
retake_variance: float = 0.5,
833+
retake_variance: float = 0.2, # MCP retake/repaint use 0.2
834834
src_audio_path: str | None = None,
835-
# Audio2Audio + LoRA
835+
# Audio2Audio + LoRA (ref_audio_strength 0.5 matches ACE-Step-MCP / pipeline default)
836836
audio2audio_enable: bool = False,
837-
ref_audio_strength: float = 0.7,
837+
ref_audio_strength: float = 0.5,
838838
lora_name_or_path: str | None = None,
839839
lora_weight: float = 0.75,
840840
cancel_check: Optional[Callable[[], bool]] = None,
@@ -884,13 +884,7 @@ def _run_ace_text2music(
884884
if not tags:
885885
raise ValueError("ACE-Step: tags/prompt cannot be empty.")
886886

887-
# Allow -1 or 0 for auto-detection (pipeline randomly selects 30-240s); otherwise clamp to minimum 1.0s
888-
seconds = float(seconds)
889-
if seconds > 0:
890-
seconds = max(1.0, seconds)
891-
elif seconds < 0 and seconds != -1:
892-
# Only -1 and 0 are valid for auto mode; reject other negative values
893-
raise ValueError("Duration must be > 0, or -1 or 0 for auto-detection.")
887+
seconds = max(1.0, float(seconds))
894888
steps = max(1, int(steps))
895889
guidance_scale = float(guidance_scale)
896890
omega_scale = float(omega_scale)
@@ -1128,9 +1122,9 @@ def generate_track_ace(
11281122
task: str = "text2music",
11291123
repaint_start: float = 0.0,
11301124
repaint_end: float = 0.0,
1131-
retake_variance: float = 0.5,
1125+
retake_variance: float = 0.2, # ACE-Step-MCP retake/repaint default
11321126
audio2audio_enable: bool = False,
1133-
ref_audio_strength: float = 0.7,
1127+
ref_audio_strength: float = 0.5, # ACE-Step-MCP / pipeline default
11341128
src_audio_path: str | None = None,
11351129
lora_name_or_path: str | None = None,
11361130
lora_weight: float = 0.75,
@@ -1180,9 +1174,8 @@ def generate_track_ace(
11801174
)
11811175

11821176
requested_total = float(target_seconds)
1183-
# Allow -1 or 0 for auto-detection (pipeline will randomly select 30-240s)
1184-
if requested_total <= 0 and requested_total not in (-1, 0):
1185-
raise ValueError("Target length must be > 0, or -1 or 0 for auto-detection.")
1177+
if requested_total <= 0:
1178+
raise ValueError("Target length must be > 0.")
11861179

11871180
fade_in_seconds = max(0.0, float(fade_in_seconds))
11881181
fade_out_seconds = max(0.0, float(fade_out_seconds))
@@ -1231,7 +1224,7 @@ def generate_track_ace(
12311224
if cfg_type not in ("apg", "cfg", "cfg_star"):
12321225
cfg_type = "apg"
12331226

1234-
# Normalise edit / Audio2Audio settings before we talk to ACE-Step.
1227+
# Normalise edit / Audio2Audio (maps to ACE-Step task_type, ref_audio_input, src_audio, audio_cover_strength).
12351228
task, audio2audio_enable, src_audio_path = _prepare_reference_audio(
12361229
task,
12371230
bool(audio2audio_enable),

music_forge_ui.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,9 +395,11 @@ def flush(self):
395395
preferences_bp,
396396
ace_step_models_bp,
397397
)
398+
from api.generate import reset_generation_queue
398399
app.register_blueprint(auth_bp, url_prefix="/api/auth")
399400
app.register_blueprint(songs_bp, url_prefix="/api/songs")
400401
app.register_blueprint(generate_bp, url_prefix="/api/generate")
402+
reset_generation_queue()
401403
app.register_blueprint(playlists_bp, url_prefix="/api/playlists")
402404
app.register_blueprint(users_bp, url_prefix="/api/users")
403405
app.register_blueprint(contact_bp, url_prefix="/api/contact")

run_local.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/bin/bash
2+
# ---------------------------------------------------------------------------
3+
# AceForge - Run locally for testing (no .app bundle)
4+
# Builds the React UI if needed, then starts the Flask server at http://127.0.0.1:5056
5+
#
6+
# Prerequisites:
7+
# - Python 3.11 and dependencies. Easiest: run ./build_local.sh once to create
8+
# venv_build and install deps; then use this script. Or create a venv and:
9+
# pip install -r requirements_ace_macos.txt (plus TTS/ACE-Step as in build_local.sh).
10+
# - Bun (only if ui/dist is missing): https://bun.sh
11+
#
12+
# Optional:
13+
# ACEFORGE_SKIP_UI_BUILD=1 - Skip UI build; use existing ui/dist/
14+
# ---------------------------------------------------------------------------
15+
16+
set -e
17+
APP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
18+
cd "$APP_DIR"
19+
20+
# Build UI if needed
21+
UI_DIR="${APP_DIR}/ui"
22+
if [ -f "$UI_DIR/package.json" ] && [ -z "${ACEFORGE_SKIP_UI_BUILD}" ]; then
23+
if [ ! -f "$UI_DIR/dist/index.html" ]; then
24+
if ! command -v bun &> /dev/null; then
25+
echo "ERROR: ui/dist missing and Bun not found. Install Bun (https://bun.sh) or run: ./scripts/build_ui.sh"
26+
exit 1
27+
fi
28+
echo "[Run] Building UI..."
29+
"${APP_DIR}/scripts/build_ui.sh"
30+
fi
31+
fi
32+
33+
# Prefer venv from full build
34+
VENV_PY="${APP_DIR}/venv_build/bin/python"
35+
if [ -x "$VENV_PY" ]; then
36+
PY="$VENV_PY"
37+
echo "[Run] Using venv_build"
38+
else
39+
PY="python3"
40+
echo "[Run] Using system python3 (install deps in a venv if you see ModuleNotFoundError)"
41+
fi
42+
43+
echo "[Run] Starting AceForge at http://127.0.0.1:5056"
44+
echo ""
45+
exec "$PY" music_forge_ui.py

ui/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,7 @@ export default function App() {
626626
const genParams = {
627627
customMode: params.customMode,
628628
songDescription: params.songDescription,
629+
prompt: params.prompt,
629630
lyrics: params.lyrics,
630631
style: params.style,
631632
title: params.title,
@@ -656,6 +657,7 @@ export default function App() {
656657
repaintingEnd: params.repaintingEnd,
657658
instruction: params.instruction,
658659
audioCoverStrength: params.audioCoverStrength,
660+
coverBlendFactor: params.coverBlendFactor,
659661
taskType: params.taskType,
660662
useAdg: params.useAdg,
661663
cfgIntervalStart: params.cfgIntervalStart,

0 commit comments

Comments
 (0)