Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Sources/FluidAudio/ModelNames.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1428,7 +1428,10 @@ public enum ModelNames {
// re-download. See mobius laishere-coreml docs/trials-and-errors.md.
public static let noise = "KokoroNoise_v2.mlmodelc"
public static let vocoder = "KokoroVocoder.mlmodelc"
public static let tail = "KokoroTail.mlmodelc"
// v2: COLA-normalized iSTFT deconv weights (raw output was exactly 1.5x
// the PyTorch reference). Renamed (not overwritten) so cached clients
// re-download. See issue #852.
public static let tail = "KokoroTail_v2.mlmodelc"

/// Auxiliary (non-CoreML) files that must accompany the mlmodelc bundles.
public static let vocab = "vocab.json"
Expand Down
2 changes: 1 addition & 1 deletion Sources/FluidAudio/TTS/KokoroAne/KokoroAneConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public enum KokoroAneConstants {
/// Default voice id for the Japanese (`ANE-ja/`) variant.
public static let defaultVoiceJapanese = "jf_alpha"

/// Output sample rate of the iSTFT in `KokoroTail.mlpackage`.
/// Output sample rate of the iSTFT in `KokoroTail_v2.mlpackage`.
public static let sampleRate = 24_000

/// BOS / EOS token id used by both `convert-coreml.py` and the iOS demo.
Expand Down
10 changes: 5 additions & 5 deletions Sources/FluidAudio/TTS/KokoroAne/KokoroAneManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -358,14 +358,14 @@ public actor KokoroAneManager {

private func wavData(from result: KokoroAneSynthesisResult) throws -> Data {
do {
// Japanese writes at the model's native level (no peak-normalization)
// so the output matches the PyTorch reference instead of being
// slammed to 0 dBFS. English/Mandarin keep peak-normalization until
// their tails get the same COLA-corrected iSTFT (#698 follow-up).
// All variants write at the model's native level (no
// peak-normalization) so the output matches the PyTorch reference
// instead of being slammed to 0 dBFS. Requires the COLA-corrected
// KokoroTail_v2 (#852).
return try AudioWAV.data(
from: result.samples,
sampleRate: Double(result.sampleRate),
normalize: variant != .japanese)
normalize: false)
} catch {
throw KokoroAneError.audioConversionFailed(error.localizedDescription)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public enum KokoroAneStage: String, CaseIterable, Sendable {
case .prosody: return "KokoroProsody.mlmodelc"
case .noise: return "KokoroNoise_v2.mlmodelc" // v2: atan2 phase-correction (HF-noise fix)
case .vocoder: return "KokoroVocoder.mlmodelc"
case .tail: return "KokoroTail.mlmodelc"
case .tail: return "KokoroTail_v2.mlmodelc" // v2: COLA-normalized iSTFT (level fix, #852)
}
}
}
4 changes: 3 additions & 1 deletion Sources/FluidAudioCLI/Commands/TTSCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -879,10 +879,12 @@ public struct TTS {
detailed = try await manager.synthesizeDetailed(
text: text, voice: resolvedVoice, speed: 1.0)
}
// Native level for all variants — matches the PyTorch reference
// now that KokoroTail_v2 carries the COLA-corrected iSTFT (#852).
let wav = try AudioWAV.data(
from: detailed.samples,
sampleRate: Double(detailed.sampleRate),
normalize: variant != .japanese)
normalize: false)
let tSynth1 = Date()

let outURL = resolveInputURL(output)
Expand Down
Loading