Home

Awesome

SwiftTTS

Swift Test

This package contains some very straightforward wrappers around TTS part of AVFoundation/AVSpeechSynthesizer to allow you using Text to Speech with ease.

Modern concurrency usage

Example

import SwiftTTS

let tts = SwiftTTS.live

tts.speak("Hello World!")

Task {
    for await isSpeaking in tts.isSpeaking() {
        print("TTS is currently \(isSpeaking ? "speaking" : "not speaking")")
    }
}

Task {
    for await progress in tts.speakingProgress() {
        print("Progress: \(Int(progress * 100))%")
    }
}

tts.setRateRatio(3/4)

tts.speak("Hello World! But slower")

Point-Free Dependencies usage

Add @Dependency(\.tts) var tts in your Reducer, you will have access to all functions mentioned above.

Example

import ComposableArchitecture
import Foundation
import SwiftTTSDependency

public struct TTS: ReducerProtocol {
    public struct State: Equatable {
        public var text = ""
        public var isSpeaking = false
        public var speakingProgress = 1.0
        public var rateRatio: Float = 1.0

        public init(
            text: String = "",
            isSpeaking: Bool = false,
            speakingProgress: Double = 1.0,
            rateRatio: Float = 1.0
        ) {
            self.text = text
            self.isSpeaking = isSpeaking
            self.speakingProgress = speakingProgress
            self.rateRatio = rateRatio
        }
    }

    public enum Action: Equatable {
        case changeRateRatio(Float)
        case speak
        case startSpeaking
        case stopSpeaking
        case changeSpeakingProgress(Double)
    }

    @Dependency(\.tts) var tts

    public init() {}

    public var body: some ReducerProtocol<State, Action> {
        Reduce { state, action in
            switch action {
            case let .changeRateRatio(rateRatio):
                state.rateRatio = rateRatio
                tts.setRateRatio(rateRatio)
                return .none
            case .speak:
                tts.speak(state.text)
                return .run { send in
                    for await isSpeaking in tts.isSpeaking() {
                        if isSpeaking {
                            await send(.startSpeaking)
                        } else {
                            await send(.stopSpeaking)
                        }
                    }
                }
            case .startSpeaking:
                state.isSpeaking = true
                return .run { send in
                    for await progress in tts.speakingProgress() {
                        await send(.changeSpeakingProgress(progress))
                    }
                }
            case .stopSpeaking:
                state.isSpeaking = false
                return .none
            case let .changeSpeakingProgress(speakingProgress):
                state.speakingProgress = speakingProgress
                return .none
            }
        }
    }
}

Combine Usage

You can instantiate/inject TTSEngine object, it has this behavior

Example

import Combine
import SwiftTTSCombine

let engine: TTSEngine = SwiftTTSCombine.Engine()
var cancellables = Set<AnyCancellable>()

engine.speak(string: "Hello World!")

engine.isSpeakingPublisher
    .sink { isSpeaking in
        print("TTS is currently \(isSpeaking ? "speaking" : "not speaking")")
    }
    .store(in: &cancellables)

engine.speakingProgressPublisher
    .sink { progress in
        print("Progress: \(Int(progress * 100))%")
    }
    .store(in: &cancellables)

engine.rateRatio = 3/4

engine.speak(string: "Hello World! But slower")

Installation

Xcode

You can add SwiftTTS libs to an Xcode project by adding it as a package dependency.

  1. From the File menu, select Swift Packages › Add Package Dependency...
  2. Enter "https://github.com/renaudjenny/swift-tts" into the package repository URL test field
  3. Select one of the three package that your are interested in. See above

As package dependency

Edit your Package.swift to add one of the library you want among the three available.

let package = Package(
    ...
    dependencies: [
        .package(url: "https://github.com/renaudjenny/swift-tts", from: "2.0.0"),
        ...
    ],
    targets: [
        .target(
            name: "<Your project name>",
            dependencies: [
                .product(name: "SwiftTTS", package: "swift-tts"), // <-- Modern concurrency
                .product(name: "SwiftTTSDependency", package: "swift-tts"), // <-- Point-Free Dependencies library wrapper
                .product(name: "SwiftTTSCombine", package: "swift-tts"), // <-- Combine wrapper
            ]),
        ...
    ]
)

App using this library