创作 — 音乐与音频制作
speech-swift 的音乐与音频制作部分由三个本地模块组成,全部通过 MLX 或 CoreML 在 Apple Silicon 上原生运行。MAGNeT 根据文本提示生成 30 秒音乐片段。音源分离(Open-Unmix)将立体声音轨拆分为四个声轨(人声 / 鼓 / 贝斯 / 其他)。语音增强(DeepFilterNet3)实时去除语音中的背景噪声。
| 模块 | 任务 | 后端 | 输出 | CLI |
|---|---|---|---|---|
| MAGNeT | 文本 → 音乐 | MLX (INT4 / INT8) | 30 秒 @ 32 kHz 单声道 | speech compose |
| Open-Unmix | 声轨分离 | MLX | 4 声轨 @ 44.1 kHz 立体声 | speech separate |
| DeepFilterNet3 | 噪声抑制 | CoreML (Neural Engine) | 48 kHz,实时 | speech denoise |
MAGNeT — 文本到音乐生成
Meta MAGNeT(单非自回归 Transformer 的掩码音频生成)的 MLX Swift 移植版本。根据自由形式的英文提示生成 30 秒、32 kHz 单声道音乐片段 —— 例如 "happy rock"、"energetic EDM with synth lead",或使用丰富的描述性文本以获得更干净的效果。
架构
加载三个组件,首次调用时下载:
| 组件 | 作用 | 来源 |
|---|---|---|
| MAGNeT 解码 LM | 作用于 4 个 EnCodec 码本的掩码非自回归 Transformer。24 层(Small, 300M)或 48 层(Medium, 1.5B)。Q/K/V/out 投影 + FFN 线性层量化(MLX-affine,group 64)。 | aufklarer/MAGNeT-{Small,Medium}-30secs-MLX-{4,8}bit |
| T5-base 文本编码器 | 用于文本条件化的 110M 参数编码器。FP32(仅编码器路径;无解码器,无 LM 头)。 | t5-base |
| EnCodec 32 kHz 解码器 | SEANet 解码器(Conv1d / ConvTranspose1d / ResnetBlock / 2 层 LSTM)+ 4 码本 Euclidean RVQ。将 LM 的离散 token 映射回 32 kHz 波形。 | mlx-community/encodec-32khz-float32 |
掩码并行解码
与自回归的 MusicGen 不同,MAGNeT 总共运行 50 次前向传递(在 4 个码本上的默认分配为 [20, 10, 10, 10]),采用余弦调度的重掩码、无分类器引导退火,以及按阶段的局部注意力窗口。阶段 0 使用完整的自注意力;阶段 1–3 使用 |q − k| ≤ 5 的局部窗口,因为更高的码本仅细化细节。
变体
| 变体 | 参数 | LM 磁盘大小 | 峰值 RSS | 耗时(M 系列,30 秒) | RTF |
|---|---|---|---|---|---|
small-int4 | 300M | 287 MB | ~1.4 GB | ~10.8 s | 0.36× |
small-int8 | 300M | 425 MB | ~1.5 GB | ~11 s | 0.37× |
medium-int4 | 1.5B | 1.36 GB | ~2.2 GB | ~36 s | 1.20× |
medium-int8 | 1.5B | 2.10 GB | ~3.0 GB | ~36 s | 1.20× |
RTF 低于 1.0 = 比实时更快。量化几乎不影响耗时 —— 主导的是注意力而非线性投影 —— 因此 INT4 的实际收益是内存而非延迟。
快速开始
import MAGNeTMusicGen
let model = try await MAGNeTMusicGen.fromPretrained(variant: .smallInt4)
let pcm = model.generate(text: "energetic upbeat rock anthem with electric guitar riffs, driving drums, bass groove")
// pcm: [Float] length 960_000 (30 s × 32 kHz mono)
try WAVWriter.write(samples: pcm, sampleRate: 32_000,
to: URL(fileURLWithPath: "out.wav"))
CLI
# Default: small-int4 (~10 s on M-series for 30 s of audio)
speech compose "happy rock" -o happy_rock.wav
# Larger model — better prompt following, ~3.5× slower
speech compose "lo-fi hip hop with mellow piano and warm vinyl crackle" \
--variant medium-int4 -o lofi.wav
# Reproducible
speech compose "energetic EDM with synth lead" --seed 42 -o edm.wav
参数:--variant {small,medium}-{int4,int8}、--temperature(退火,默认 3.0)、--top-p(默认 0.9)、--cfg-max / --cfg-min(默认 10.0 / 1.0)、--steps "20,10,10,10"(每个码本的迭代次数)、--seed。
像 "happy rock" 这样的短标签可以工作但感觉单薄。提到 乐器 + 节奏 + 情绪 的描述性提示能显著提高连贯性 —— 在我们的质量测试中,更丰富的提示带来了更高的过零率(0.116 vs 0.093,即更多高频细节)和零削波。比较:
"happy rock"— 单薄"energetic upbeat rock anthem with electric guitar riffs, driving drums, bass groove"— 更丰富,通常更好
包与许可
所有四个 MLX 包均派生自 facebook/magnet-small-30secs 和 facebook/magnet-medium-30secs,继承 Meta 的许可:CC-BY-NC 4.0 — 仅限非商业用途。生成的音频遵循相同的限制。
音源分离 — Open-Unmix(4 声轨)
Open-Unmix HQ / UMX-L 移植到 MLX。通过每个声轨的 BiLSTM 预测器和多通道 Wiener-EM 后置滤波器将立体声混音拆分为四个声轨 —— 人声、鼓、贝斯、其他乐器 —— 全程在 MLX 上端到端运行,通过逆 STFT 完成。M 系列上 30 秒音频的实际 RTF 约为 0.031(比实时快 32 倍)。
# Split mix.wav into vocals/drums/bass/other.wav next to it
speech separate mix.wav
# Or keep stems together
speech separate mix.wav --output stems/
import SourceSeparation
let separator = try await SourceSeparator.fromPretrained()
let stems = try separator.separate(audio: stereoSamples, sampleRate: 44_100)
// stems.vocals, stems.drums, stems.bass, stems.other — each [Float]
完整的架构、调优和基准测试说明请参见音源分离指南。
语音增强 — DeepFilterNet3
运行在神经引擎(CoreML)上的 DeepFilterNet3。使用 2.1M 参数模型实时去除 48 kHz 语音中的背景噪声 —— 足够小,可作为 ASR 流水线的预处理步骤并行运行。
speech denoise noisy.wav -o clean.wav
import SpeechEnhancement
let enhancer = try await SpeechEnhancer.fromPretrained()
let clean = try enhancer.enhance(audio: noisy, sampleRate: 48_000)
完整配置请参见语音增强指南。
选择合适的工具
| 你想要… | 使用 |
|---|---|
| 从文本提示生成音乐 | MAGNeT (speech compose) |
| 从现有音轨中提取人声或鼓声 | Open-Unmix (speech separate) |
| 在转录前清理嘈杂的语音 | DeepFilterNet3 (speech denoise) |
| 将文本转换为语音(语音合成) | VoxCPM2 or Qwen3-TTS |