Summary
On macOS 14 (Apple M1 (Virtual), a GitHub-hosted macos-14 runner), KokoroAneManager.synthesize fails at the vocoder stage under every KokoroAneComputeUnits setting. The package declares .macOS(.v14) and KokoroAne carries no @available gate, so this reads as a supported configuration that nothing currently exercises — every workflow in .github/workflows runs on macos-15.
The compute-unit setting does change CoreML's behaviour; it just moves the failure rather than clearing it. The four presets split cleanly into two groups.
ANE-targeting presets — default, all-ane:
predictionFailed(stage: "vocoder", underlying: Error Domain=com.apple.CoreML Code=0
"Failed to prepare the model for predictions. ML program was KokoroVocoder and the
function name was main."
NSUnderlyingError=... Error Domain=com.apple.CoreML Code=0
"E5RT: Output rank has changed after reshaping espresso network for
blob = anchor_classic_cpu (11)")
Non-ANE presets — cpu-and-gpu, cpu-only:
predictionFailed(stage: "vocoder", underlying: Error Domain=com.apple.CoreML Code=1
"Invalid shape for output feature 'anchor'."
NSUnderlyingError=... Error Domain=com.apple.CoreML Code=1
"According to model description, feature 'anchor' must be of rank 1, instead got a
multi-array value of rank 2.")
cpu-only fails identically to cpu-and-gpu, so the rank mismatch is not GPU-specific — it is on the CPU path of the vocoder.
Environment
|
|
| FluidAudio |
0.14.8 (pinned exactly) |
| OS |
macOS 14.8.7, build 23J520 |
| Arch |
arm64, Apple M1 (Virtual) |
| Runner |
GitHub-hosted macos-14 |
| Toolchain |
Xcode 16.2 (Swift 6) |
| Variant |
.english, voice af_heart |
For contrast, the same code path with the same staged model bundle synthesizes fine on a physical M2 (macOS 26.5.2) under all four presets.
Why this looks like a gap rather than misuse
Package.swift at v0.14.8 declares platforms: [.macOS(.v14), .iOS(.v17)].
- KokoroAne has no
@available annotation anywhere under Sources/FluidAudio/TTS/. Qwen3 does — @available(macOS 15, iOS 18, *) on Qwen3AsrManager, Qwen3AsrModels, Qwen3StreamingManager — so per-feature OS gating is clearly the established pattern when a feature needs macOS 15. Its absence on KokoroAne reads as intentional.
Documentation/TTS/ makes no macOS 15 claim.
- Every workflow under
.github/workflows/ runs on macos-15, so nothing exercises the declared floor.
If macOS 14 is in fact not supported for KokoroAne, an @available(macOS 15, ...) gate would turn this runtime failure into a compile-time one and answer the question at the API surface. That would be a perfectly good resolution — it just is not the current state.
Possibly related
On the physical M2, cpu-and-gpu emits E5RT "Data-dependent shapes were disabled" diagnostics to stdout and recovers internally; synthesis succeeds. The rank-2-instead-of-rank-1 result on the virtual M1 may be the same data-dependent-shape path failing to recover rather than a separate defect — but I have not established that link and am flagging it only as a lead.
Separately, those diagnostics going to stdout is awkward for any caller streaming WAV bytes there; that may deserve its own issue if it is not already known.
Reproduction
Honest caveat up front: I hit this through fluidaudio-rs, a Rust binding, not from pure Swift. The bridge is thin at the failing point — it calls manager.synthesize(text:voice:speed:) directly, and the thrown value is FluidAudio's own KokoroAneError.predictionFailed, raised in KokoroAneSynthesizer.predict around model.prediction(from:). I do not have a macOS 14 host to run a Swift-only case on, so I have not confirmed the binding is irrelevant, only that it does nothing between the call and the error.
The Swift equivalent should be:
let manager = KokoroAneManager(
variant: .english,
defaultVoice: "af_heart",
computeUnits: KokoroAneComputeUnits(preset: .cpuOnly))
try await manager.initialize(preloadVoices: ["af_heart"])
let audio = try await manager.synthesize(text: "Hello world", voice: "af_heart", speed: 1.0)
initialize succeeds — it only downloads and loads the mlmodelcs, and issues no prediction. The failure lands on the first synthesize.
To reproduce in CI, add a macos-14 job and select Xcode 16 explicitly: that image's default toolchain is Swift 5.10, which cannot build a Swift-tools-6.0 package, and it ships no plain Xcode_16.app — only Xcode_16.1 / Xcode_16.2.
Full run with all four presets, per-preset stderr and host details:
https://github.com/FluidInference/fluidaudio-rs/actions/runs/31007985381
Summary
On macOS 14 (
Apple M1 (Virtual), a GitHub-hostedmacos-14runner),KokoroAneManager.synthesizefails at the vocoder stage under everyKokoroAneComputeUnitssetting. The package declares.macOS(.v14)and KokoroAne carries no@availablegate, so this reads as a supported configuration that nothing currently exercises — every workflow in.github/workflowsruns onmacos-15.The compute-unit setting does change CoreML's behaviour; it just moves the failure rather than clearing it. The four presets split cleanly into two groups.
ANE-targeting presets —
default,all-ane:Non-ANE presets —
cpu-and-gpu,cpu-only:cpu-onlyfails identically tocpu-and-gpu, so the rank mismatch is not GPU-specific — it is on the CPU path of the vocoder.Environment
Apple M1 (Virtual)macos-14.english, voiceaf_heartFor contrast, the same code path with the same staged model bundle synthesizes fine on a physical M2 (macOS 26.5.2) under all four presets.
Why this looks like a gap rather than misuse
Package.swiftatv0.14.8declaresplatforms: [.macOS(.v14), .iOS(.v17)].@availableannotation anywhere underSources/FluidAudio/TTS/. Qwen3 does —@available(macOS 15, iOS 18, *)onQwen3AsrManager,Qwen3AsrModels,Qwen3StreamingManager— so per-feature OS gating is clearly the established pattern when a feature needs macOS 15. Its absence on KokoroAne reads as intentional.Documentation/TTS/makes no macOS 15 claim..github/workflows/runs onmacos-15, so nothing exercises the declared floor.If macOS 14 is in fact not supported for KokoroAne, an
@available(macOS 15, ...)gate would turn this runtime failure into a compile-time one and answer the question at the API surface. That would be a perfectly good resolution — it just is not the current state.Possibly related
On the physical M2,
cpu-and-gpuemits E5RT"Data-dependent shapes were disabled"diagnostics to stdout and recovers internally; synthesis succeeds. The rank-2-instead-of-rank-1 result on the virtual M1 may be the same data-dependent-shape path failing to recover rather than a separate defect — but I have not established that link and am flagging it only as a lead.Separately, those diagnostics going to stdout is awkward for any caller streaming WAV bytes there; that may deserve its own issue if it is not already known.
Reproduction
Honest caveat up front: I hit this through fluidaudio-rs, a Rust binding, not from pure Swift. The bridge is thin at the failing point — it calls
manager.synthesize(text:voice:speed:)directly, and the thrown value is FluidAudio's ownKokoroAneError.predictionFailed, raised inKokoroAneSynthesizer.predictaroundmodel.prediction(from:). I do not have a macOS 14 host to run a Swift-only case on, so I have not confirmed the binding is irrelevant, only that it does nothing between the call and the error.The Swift equivalent should be:
initializesucceeds — it only downloads and loads the mlmodelcs, and issues no prediction. The failure lands on the firstsynthesize.To reproduce in CI, add a
macos-14job and select Xcode 16 explicitly: that image's default toolchain is Swift 5.10, which cannot build a Swift-tools-6.0 package, and it ships no plainXcode_16.app— onlyXcode_16.1/Xcode_16.2.Full run with all four presets, per-preset stderr and host details:
https://github.com/FluidInference/fluidaudio-rs/actions/runs/31007985381