Architecture
speech-swift est organisé comme un package Swift modulaire avec des protocoles partagés, des modules de modèles indépendants et une CLI unifiée. Toute l'inférence s'exécute sur l'appareil en utilisant MLX (GPU Metal) ou CoreML (Neural Engine).
Graphe de dépendances des modules
┌──────────┐
│ AudioCLI │ (point d'entrée)
└────┬─────┘
│
┌──────┴──────┐
│ AudioCLILib │ (commandes)
└──────┬──────┘
│
┌─────────┬───────┼───────┬──────────┬──────────────┐
│ │ │ │ │ │
┌────┴───┐ ┌──┴──┐ ┌──┴──┐ ┌─┴────┐ ┌───┴────┐ ┌──────┴───────┐
│Qwen3ASR│ │Qwen3│ │Cosy │ │Perso-│ │Speech- │ │ Speech- │
│Parakeet│ │ TTS │ │Voice│ │naPlex│ │ VAD │ │Enhancement │
└────┬───┘ └──┬──┘ └──┬──┘ └──┬───┘ └───┬───┘ └──────┬───────┘
│ │ │ │ │ │
└────────┴───────┼───────┴─────────┘ │
│ │
┌──────┴──────┐ │
│ Qwen3Common │ (couches partagées) │
└──────┬──────┘ │
│ │
┌──────┴──────┐ │
│ AudioCommon │ ◄──────────────────────┘
└─────────────┘ (protocoles, E/S audio)MOSS Transcribe Diarize
MossTranscribe renvoie des segments horodatés attribués aux locuteurs via des backends natifs CoreML et MLX. CoreML utilise un état fixe de 1 024 tokens pour les enregistrements courts. MLX emploie un contexte dynamique de 131 072 tokens, des poids de décodeur affine INT5/INT8 et des caches KV FP16/INT8 optionnels. Les deux runtimes sont hors ligne et autorégressifs, sans streaming.
VoiceChat 11B
Tâche et référence : speech-to-speech duplex ; SALM-Duplex: Efficient and Direct Duplex Modeling for Speech-to-Speech Language Model (Interspeech 2025), cité par la fiche VoiceChat amont de NVIDIA.
Runtime complet, M5 Pro 48 Go, Release, cadence live de 80 ms : l'INT5 avec têtes protégées atteint environ 8.69 Go de RSS maximal ; trois RTF contrôlés du pipeline complet ont donné 0.96, 0.96 et 0.99. Les performances INT8 optimisées n'ont pas encore été remesurées.
VoiceChat implémente le chemin audio-à-audio MLX natif complet : perception FastConformer causale, canaux duplex texte/fonction Nemotron-H, décodeur EAR-TTS autonome conditionné par le texte avec huit itérations MaskGIT et codec neuronal à 22,05 kHz. Le streaming conserve des caches bornés d'attention et de convolution causale par couche, tandis que la fenêtre live stable de huit trames du codec utilise un graphe compilé. Chaque trame d'entrée de 80 ms produit une décision de langage, 31 codes RVQ et exactement 1 764 échantillons de sortie. Le chargeur exige un bundle complet encoder/ + llm/ + tts/ et refuse les anciens exports limités à la compréhension. INT5 maintient désormais un RTF global sous 1 sur le M5 Pro testé, bien que la marge p95 par trame reste faible.
Backends d'inférence
| Backend | Matériel | Modèles |
|---|---|---|
| MLX | GPU Metal | Qwen3-ASR, Qwen3-TTS, CosyVoice3, IndexTTS2, Qwen3.5-Chat, PersonaPlex, VoiceChat 11B, Omnilingual ASR (300M / 1B / 3B / 7B), Cohere Transcribe 2B, Voxtral Mini 3B, Pyannote, Silero VAD, WeSpeaker, MOSS Transcribe Diarize, SpeechBrain ECAPA LID |
| CoreML | Neural Engine | Encodeur Qwen3-ASR (hybride), Parakeet TDT, Parakeet EOU streaming, Omnilingual ASR 300M, Kokoro-82M, Qwen3.5-Chat (optionnel), diarisation Sortformer, DeepFilterNet3, Silero VAD (optionnel), WeSpeaker (optionnel), MOSS Transcribe Diarize, SpeechBrain ECAPA LID |
| Accelerate | CPU (SIMD) | Prétraitement audio (STFT, mel, FFT), traitement du signal |
Format des poids de modèles
Les modèles MLX utilisent le format safetensors avec une quantification 4 bits ou 8 bits (taille de groupe 64). Les modèles CoreML utilisent le format compilé .mlmodelc. Les scripts de conversion dans scripts/ convertissent depuis des checkpoints PyTorch.
Cohere et Voxtral proposent aussi des bundles MLX INT5 affines. MLX ne prend pas en charge INT7 affine ; INT8 est l’option de meilleure qualité prise en charge.
| Modèle | Paramètres | Quantification | Taille sur disque |
|---|---|---|---|
| Qwen3-ASR 0.6B (MLX) | ~600M | 4 bits / 8 bits | 680 Mo / 1,0 Go |
| Qwen3-ASR 0.6B (CoreML) | ~186M (encodeur) | INT8 | ~180 Mo |
| Qwen3-ASR 1.7B (MLX) | ~1,7B | 4 bits / 8 bits | 2,1 Go / 3,2 Go |
| Parakeet-TDT 0.6B (CoreML) | ~600M | INT8 | 500 Mo |
| Whisper Large-v3 Turbo (CoreML) | 809M | FP16 | 1.6 GB |
| MOSS Transcribe Diarize 0.9B (MLX) | 908.5M | FP16 audio + INT5 / INT8 decoder | 987.0 MiB / 1,200.1 MiB |
| MOSS Transcribe Diarize 0.9B (CoreML) | ~900M | FP16 / INT8 block-32 | 1.7 GB / 1.2 GB |
| Parakeet-EOU 120M (CoreML) | ~120M | INT8 | ~120 Mo |
| Omnilingual-ASR-CTC 300M (CoreML) | 326M | INT8 | 312 Mo |
| Omnilingual-ASR-CTC 300M (MLX) | 326M | 4 bits / 8 bits | 193 Mo / 342 Mo |
| Omnilingual-ASR-CTC 1B (MLX) | 1,01B | 4 bits / 8 bits | 549 Mo / 1006 Mo |
| Omnilingual-ASR-CTC 3B (MLX) | ~3B | 4 bits / 8 bits | 1,71 Go / 3,16 Go |
| Omnilingual-ASR-CTC 7B (MLX) | ~7B | 4 bits / 8 bits | 3,55 Go / 6,63 Go |
| Cohere Transcribe 2B (MLX) | 2B | FP16 / INT5 / INT8 | 3.85 / 1.62 / 2.25 GiB |
| Voxtral Mini 3B 2507 (MLX) | 3B | FP16 / INT5 / INT8 | 8.71 / 3.77 / 5.18 GiB |
| Qwen3-ForcedAligner 0.6B (MLX) | ~600M | 4 bits / 8 bits | 979 Mo / 1,4 Go |
| Qwen3-ForcedAligner 0.6B (CoreML) | ~600M | INT4 / INT8 | 630 Mo / 1,0 Go |
| Qwen3-TTS 0.6B (MLX) | ~600M | 4 bits / 8 bits | 1,7 Go / 2,4 Go |
| Qwen3-TTS 1.7B (MLX) | ~1,7B | 4 bits / 8 bits | 3,2 Go / 4,8 Go |
| CosyVoice3 0.5B (MLX) | ~500M | LLM 4 bits | ~1,2 Go |
| IndexTTS2 expanded bundle (MLX) | 1.5B-class | FP16 + auxiliary models | ~4.8 GB |
| Kokoro-82M (CoreML) | 82M | INT8 (1 bucket) | ~89 Mo |
| Qwen3.5-Chat 0.8B (MLX) | ~800M | INT4 | 418 Mo |
| Qwen3.5-Chat 0.8B (CoreML) | ~800M | INT8 | 981 Mo |
| PersonaPlex 7B (MLX) | ~7B | 4 bits / 8 bits | 4,9 Go / 9,1 Go |
| VoiceChat 11B (MLX) | ~11B | INT5 / INT8 | 8.56 GB / 12.11 GB |
| Pyannote VAD (MLX) | ~1,49M | float32 | ~5,7 Mo |
| Silero VAD v5 | ~309K | float32 | ~1,2 Mo (MLX et CoreML) |
| WeSpeaker ResNet34 | ~6,6M | float32 | ~25 Mo (MLX et CoreML) |
| SpeechBrain ECAPA VoxLingua107 | 21.25M | FP16 | ~40.6 MiB (MLX) / ~40.8 MiB (CoreML) |
| ReDimNet2-B6 | 12,3M | float16 | ~25 Mio (CoreML) |
| Pyannote Community-1 (CoreML) | 8.35M | float32 + native VBx | ~32 MB |
| Sortformer (CoreML) | — | float16 | ~50 Mo |
| DeepFilterNet3 (CoreML) | ~2,1M | FP16 | ~4,2 Mo |
| LocalVQE v1.4-AEC (CoreML + C++) | 200K + 2 742 | FP16 + FP32 | ~732 Ko |
Optimisations de performance
- MLX compile() — Fusion de noyaux pour les boucles autorégressives. Talker utilise
compile(shapeless: true), Code Predictor utilisecompile(shapeless: false)avec des tailles de cache fixes. - Bibliothèque de shaders Metal — Le metallib pré-compilé évite environ 5× de surcoût de compilation JIT. Compilé via
scripts/build_mlx_metallib.sh. - Décodage de codec par chunks — Le décodeur TTS traite l'audio par chunks de 25 trames avec chevauchement de contexte de 10 trames pour éviter les timeouts GPU.
- CFG à batch doublé — Le DiT de CosyVoice3 divise par deux les passes de flow matching en groupant conditionnel + inconditionnel ensemble.
- RoPE fusionné — Utilise
MLXNN.RoPEadossé à un noyau Metal plutôt qu'une rotation manuelle. - Fusion BN — La normalisation par batch de WeSpeaker est fusionnée dans les poids Conv2d au moment de la conversion.
Traitement audio
Toutes les E/S audio utilisent du PCM Float32. Le rééchantillonnage interne gère la conversion de format :
| Modèle | Taux attendu | Format |
|---|---|---|
| Qwen3-ASR | 16 kHz | Mono Float32 |
| Cohere Transcribe 2B | 16 kHz | Mono Float32 |
| Voxtral Mini 3B | 16 kHz | Mono Float32 |
| Qwen3-TTS | 24 kHz en sortie | Mono Float32 |
| CosyVoice3 | 24 kHz en sortie | Mono Float32 |
| Kokoro-82M | 24 kHz en sortie | Mono Float32 |
| PersonaPlex | 24 kHz E/S | Mono Float32 |
| Pyannote VAD | 16 kHz | Mono Float32 |
| Silero VAD | 16 kHz | Mono Float32 |
| WeSpeaker | 16 kHz | Mono Float32 |
| SpeechBrain ECAPA LID | 16 kHz | Mono Float32 |
| ReDimNet2-B6 | 16 kHz | Mono Float32 |
| DeepFilterNet3 | 48 kHz | Mono Float32 |
Structure des sources
Sources/
AudioCommon/ Protocoles partagés, E/S audio, capture de la
sortie système (SystemAudioTap), téléchargeur
HuggingFace, SentencePieceModel (lecteur protobuf)
MLXCommon/ Utilitaires MLX : chargement des poids, aides QuantizedLinear,
aide d'attention multi-tête SDPA, budget Metal
Qwen3Common/ Composants de modèle partagés (cache KV, RoPE, quantification)
Qwen3ASR/ Qwen3-ASR parole vers texte
ParakeetASR/ Parakeet TDT parole vers texte (CoreML)
ParakeetStreamingASR/ Dictée streaming Parakeet EOU 120M (CoreML)
OmnilingualASR/ Meta wav2vec2 + CTC, 1 672 langues
(CoreML 300M + MLX 300M / 1B / 3B / 7B)
CohereTranscribeASR/ Cohere Transcribe 2B speech-to-text (MLX)
VoxtralASR/ Voxtral Mini 3B speech-to-text (MLX)
Qwen3TTS/ Qwen3-TTS texte vers parole
CosyVoiceTTS/ CosyVoice3 texte vers parole
KokoroTTS/ Kokoro-82M texte vers parole (CoreML)
Qwen3Chat/ Chat LLM embarqué Qwen3.5-0.8B (MLX + CoreML)
PersonaPlex/ PersonaPlex parole-à-parole
SpeechVAD/ VAD (Silero + Pyannote), diarisation, empreintes de locuteur
SpeechLanguageID/ Identification de la langue parlée (SpeechBrain ECAPA, MLX + CoreML, 107 étiquettes)
SpeechEnhancement/ Suppression de bruit DeepFilterNet3 (CoreML)
SourceSeparation/ Open-Unmix HQ / UMX-L + HTDemucs (Demucs v4) music source separation (MLX, 4 stems)
MAGNeTMusicGen/ MAGNeT text-to-music generation (MLX, 30 s @ 32 kHz, INT4/INT8)
VoxCPM2TTS/ VoxCPM2 text-to-speech (MLX, 48 kHz, voice cloning + voice design)
IndexTTS2TTS/ IndexTTS2 voice cloning (MLX, semantic GPT + emotion/tempo/pause control + S2Mel + BigVGAN)
VibeVoiceTTS/ VibeVoice long-form / multi-speaker TTS (MLX, EN/ZH)
MADLADTranslation/ MADLAD-400 many-to-many translation (MLX, 400+ languages)
AudioCLILib/ Implémentations des commandes CLI
AudioCLI/ Point d'entrée CLI
scripts/ Conversion de modèles (PyTorch → MLX/CoreML), benchmarking
Tests/ Tests unitaires et d'intégration
Examples/ Applications de démonstration (PersonaPlexDemo, SpeechDemo)