Use this file to discover all available pages before exploring further.
The official Swift library for the Typecast API. Convert text to lifelike speech using AI-powered voices.Compatible with Swift 5.9+ and supports all Apple platforms: iOS, macOS, tvOS, watchOS, and visionOS.
ssfm-v30 offers two emotion control modes: Preset and Smart.
Smart Mode
Preset Mode
Convenience Method
Let the AI infer emotion from context:
let request = TTSRequest( voiceId: "tc_672c5f5ce59fac2a48faeaee", text: "Everything is going to be okay.", model: .ssfmV30, prompt: .smart(SmartPrompt( previousText: "I just got the best news!", // Optional context nextText: "I can't wait to celebrate!" // Optional context )))let response = try await client.textToSpeech(request)
Explicitly set emotion with preset values:
let request = TTSRequest( voiceId: "tc_672c5f5ce59fac2a48faeaee", text: "I am so excited to show you these features!", model: .ssfmV30, prompt: .preset(PresetPrompt( emotionPreset: .happy, // normal, happy, sad, angry, whisper, toneup, tonedown emotionIntensity: 1.5 // Range: 0.0 to 2.0 )))let response = try await client.textToSpeech(request)
Use the convenience method for quick emotion control:
let audio = try await client.speak( "I'm so excited!", voiceId: "tc_672c5f5ce59fac2a48faeaee", emotion: .happy, intensity: 1.5)
Stream audio chunks in real-time for low-latency playback:
import AVFoundationimport Typecastlet engine = AVAudioEngine()let playerNode = AVAudioPlayerNode()let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 32000, channels: 1, interleaved: true)!engine.attach(playerNode)engine.connect(playerNode, to: engine.mainMixerNode, format: format)try engine.start()playerNode.play()let stream = try await client.textToSpeechStream(request)var first = truefor try await chunk in stream { var pcmData = chunk if first { pcmData = chunk.dropFirst(44) // Skip 44-byte WAV header first = false } let buffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(pcmData.count / 2))! buffer.frameLength = buffer.frameCapacity pcmData.withUnsafeBytes { ptr in buffer.int16ChannelData!.pointee.update(from: ptr.bindMemory(to: Int16.self).baseAddress!, count: Int(buffer.frameLength)) } playerNode.scheduleBuffer(buffer)}
WAV streaming format: 32000 Hz, 16-bit, mono PCM. The first chunk includes a 44-byte WAV header (size = 0xFFFFFFFF); subsequent chunks are raw PCM only. For MP3: 320 kbps, 44100 Hz, each chunk is independently decodable. Use Typecast.OutputStream to avoid collision with Foundation.OutputStream. The streaming endpoint does not support volume or targetLufs.
import Typecastimport WatchKitclass WatchTTSManager { private let client = TypecastClient(apiKey: "YOUR_API_KEY") func speak(_ text: String) async throws { let audio = try await client.speak(text, voiceId: "tc_672c5f5ce59fac2a48faeaee") // Save to temporary file and play let tempURL = FileManager.default.temporaryDirectory .appendingPathComponent("speech.\(audio.format.rawValue)") try audio.audioData.write(to: tempURL) // Use WKAudioFilePlayer for watchOS let asset = WKAudioFileAsset(url: tempURL) let playerItem = WKAudioFilePlayerItem(asset: asset) let player = WKAudioFilePlayer(playerItem: playerItem) player.play() }}