# Architecture
> Full technical reference for acestep.cpp. For a quick start guide, see [README.md](../README.md).
# acestep.cpp
Portable C++17 implementation of ACE-Step 1.5 music generation using GGML.
Text + lyrics in, stereo 48kHz MP3 or WAV out. Runs on CPU, CUDA, ROCm, Metal, Vulkan.
## Build
```bash
git submodule update --init
mkdir build && cd build
# macOS (Metal + Accelerate BLAS auto-enabled)
cmake ..
# Linux with NVIDIA GPU
cmake .. -DGGML_CUDA=ON
# Linux with AMD GPU (ROCm)
cmake .. -DGGML_HIP=ON
# Linux with Vulkan
cmake .. -DGGML_VULKAN=ON
cmake --build . --config Release -j$(nproc)
```
### Windows
Install [Visual C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/)
(select "Desktop development with C++" workload) and optionally the
[CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) and/or the
[Vulkan SDK](https://vulkan.lunarg.com/sdk/home).
```cmd
git submodule update --init
call "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"
mkdir build
cd build
rem NVIDIA GPU
cmake .. -DGGML_CUDA=ON
rem AMD/Intel GPU (Vulkan)
cmake .. -DGGML_VULKAN=ON
rem all backends (CUDA + Vulkan + CPU, runtime loading)
cmake .. -DGGML_CPU_ALL_VARIANTS=ON -DGGML_CUDA=ON -DGGML_VULKAN=ON -DGGML_BACKEND_DL=ON
cmake --build . --config Release -j %NUMBER_OF_PROCESSORS%
```
Builds seven binaries: `ace-lm` (LLM), `ace-synth` (DiT + VAE), `ace-server` (HTTP server), `ace-understand` (reverse: audio -> metadata), `neural-codec` (VAE encode/decode), `mp3-codec` (MP3 encoder/decoder) and `quantize` (GGUF requantizer).
## Models
Pre-quantized GGUFs on [Hugging Face](https://huggingface.co/Serveurperso/ACE-Step-1.5-GGUF).
```bash
pip install hf
./models.sh # Q8_0 turbo essentials (~7.7 GB)
./models.sh --all # every model, every quant (~97 GB)
./models.sh --quant Q6_K # pick a specific quant (Q4_K_M, Q5_K_M, Q6_K, Q8_0, BF16)
./models.sh --sft # add SFT DiT variant
./models.sh --shifts # add shift1/shift3/continuous variants
```
Default downloads 4 files into `models/`:
| GGUF | Arch | Size |
|------|------|------|
| Qwen3-Embedding-0.6B-Q8_0.gguf | text encoder (28L, H=1024) | 748 MB |
| acestep-5Hz-lm-4B-Q8_0.gguf | Qwen3 causal LM | 4.2 GB |
| acestep-v15-turbo-Q8_0.gguf | DiT 2B + CondEncoder (24L, H=2048) | 2.4 GB |
| vae-BF16.gguf | AutoencoderOobleck | 322 MB |
Three LM sizes: 0.6B (fast), 1.7B, 4B (best quality).
Six DiT variants: turbo, sft, base, turbo-shift1, turbo-shift3, turbo-continuous.
XL (4B DiT) variants: xl-turbo, xl-sft, xl-base (32L, H=2560, higher quality, ~9.5 GB BF16).
VAE is always BF16 (small, bandwidth-bound, quality-critical).
Building GGUFs from source (checkpoints + convert)
If you want to convert from the original safetensors yourself:
```bash
pip install gguf hf
./checkpoints.sh # download raw HF checkpoints (turbo + 4B LM)
./checkpoints.sh --all # all variants (SFT, shift1/3, 0.6B/1.7B LM)
python3 convert.py # convert all checkpoints to GGUF (models/)
./quantize.sh # quantize BF16 -> Q4_K_M/Q5_K_M/Q6_K/Q8_0
```
`checkpoints.sh` downloads safetensors, config.json, and tokenizer files
into `checkpoints/`. `convert.py` packs everything into self-contained
GGUF files in `models/`, bundling BPE tokenizer, silence_latent, and
config metadata so no external file is needed at runtime.
## CLI
`ace-lm` generates lyrics and audio codes, `ace-synth` synthesizes audio.
The input JSON is never modified. Output is always numbered: `request0.json`.
```bash
cat > /tmp/request.json << 'EOF'
{
"caption": "Upbeat pop rock with driving guitars and catchy hooks",
"inference_steps": 8,
"shift": 3.0,
"vocal_language": "fr"
}
EOF
# LLM: request.json -> request0.json (enriched with metadata + lyrics + codes)
./ace-lm \
--request /tmp/request.json \
--lm models/acestep-5Hz-lm-4B-Q8_0.gguf
# DiT+VAE: request0.json -> request00.mp3
./ace-synth \
--request /tmp/request0.json \
--embedding models/Qwen3-Embedding-0.6B-Q8_0.gguf \
--dit models/acestep-v15-turbo-Q8_0.gguf \
--vae models/vae-BF16.gguf
```
With an adapter (LoRA today, PEFT directory or ComfyUI single file):
```bash
# PEFT directory (contains adapter_model.safetensors + adapter_config.json)
./ace-synth \
--request /tmp/request0.json \
--embedding models/Qwen3-Embedding-0.6B-Q8_0.gguf \
--dit models/acestep-v15-turbo-Q8_0.gguf \
--vae models/vae-BF16.gguf \
--adapter /path/to/peft-adapter
# ComfyUI single .safetensors file (alpha baked in, no config needed)
./ace-synth \
--request /tmp/request0.json \
--embedding models/Qwen3-Embedding-0.6B-Q8_0.gguf \
--dit models/acestep-v15-turbo-Q8_0.gguf \
--vae models/vae-BF16.gguf \
--adapter best_sft_v2_2338_comfyui.safetensors
```
Generate multiple songs at once with `lm_batch_size` in the JSON:
```bash
# 2 different songs from one prompt (different lyrics, codes, metadata)
cat > /tmp/request.json << 'EOF'
{
"caption": "Upbeat pop rock anthem with driving guitars and catchy hooks",
"vocal_language": "fr",
"lm_batch_size": 2
}
EOF
# LM: request.json (lm_batch_size=2) -> request0.json, request1.json
./ace-lm \
--request /tmp/request.json \
--lm models/acestep-5Hz-lm-4B-Q8_0.gguf
# DiT+VAE: both requests in one GPU batch -> request00.mp3, request10.mp3
./ace-synth \
--request /tmp/request0.json /tmp/request1.json \
--embedding models/Qwen3-Embedding-0.6B-Q8_0.gguf \
--dit models/acestep-v15-turbo-Q8_0.gguf \
--vae models/vae-BF16.gguf
```
`lm_batch_size` controls how many songs the LM generates. User-provided
fields are preserved in all outputs. Empty fields are filled independently
per batch item, producing genuinely different songs.
ace-synth takes all request files as CLI arguments and runs them in a
single GPU batch.
Transform an existing song with `--src-audio` (no LLM needed):
```bash
cat > /tmp/cover.json << 'EOF'
{
"task_type": "cover",
"caption": "Jazz piano cover with brushed drums and walking bass",
"lyrics": "[Instrumental]"
}
EOF
./ace-synth \
--src-audio song.wav \
--request /tmp/cover.json \
--embedding models/Qwen3-Embedding-0.6B-Q8_0.gguf \
--dit models/acestep-v15-turbo-Q8_0.gguf \
--vae models/vae-BF16.gguf \
```
Ready-made examples in `examples/`:
```bash
cd examples
./simple.sh # caption only, LLM fills everything
./simple-batch.sh # 2 songs from one prompt (lm_batch_size=2)
./partial.sh # caption + lyrics + duration
./full.sh # all metadata provided
./dit-only.sh # skip LLM, DiT from noise
./server-turbo.sh # start HTTP server (turbo model)
./server-sft.sh # start HTTP server (SFT model)
./client.sh # test server (single song)
./client-batch.py # test server batch (2 songs)
./client-understand.sh