首页 > 解决方案 > 如何将文本到语音的输出写入 Swift UI 中的文件?

问题描述

我正在尝试将文本到语音的输出写入声音文件。我基本上从这个 stackoverflow 答案中复制了代码,我发现它在故事板应用程序中工作,但当我迁移到 SwiftUI 时不再工作。

以下是一个完整的应用程序,只需将其粘贴到新的 SwiftUI 应用程序中的 ContentView 中并点击运行即可。

import SwiftUI
import AVFoundation

struct ContentView: View {
    var body: some View {
        Button(action: runSpeech) {
            Text("Button")
        }
    }
    
    func runSpeech() {
        let fileURL = generateSpeech("hello world", 1.0)
        
        if FileManager.default.fileExists(atPath: fileURL!.path) {
            print(" Speech file exists at \(fileURL!)")
        } else {
            print(" no file exists at \(fileURL!)")
        }
        return
}
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

func generateSpeech(_ speech: String, _ speechRate: Float) -> URL? {
    let synth = AVSpeechSynthesizer()
    let myUtterance = AVSpeechUtterance(string: speech)
    myUtterance.rate = speechRate
    myUtterance.voice = AVSpeechSynthesisVoice(language: "en")!
    myUtterance.postUtteranceDelay = 2

    let dataPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first

    do {
        try FileManager.default.createDirectory(atPath: dataPath?.path ?? "", withIntermediateDirectories: true, attributes: nil)
    } catch let error as NSError {
        print("Error creating directory: \(error.localizedDescription)")
    }
    let fileName = "myspeech.caf"
    
    let fileURL = dataPath?.appendingPathComponent(fileName)

    if FileManager.default.fileExists(atPath: fileURL!.path) {
        print("Speech file exists at \(fileURL!)")
        return fileURL
    }
    
    print("Speech file does not exist at \(fileURL!)")
   
    var output: AVAudioFile?
    
    synth.write(myUtterance) { (buffer: AVAudioBuffer) in
        print("callback")
        guard let pcmBuffer = buffer as? AVAudioPCMBuffer else {
            fatalError("unknown buffer type: \(buffer)")
        }
        if pcmBuffer.frameLength == 0 {
            // done
        } else {
            // append buffer to file
             do {
                if output == nil {
                    try output = AVAudioFile(
                        forWriting: fileURL!,
                        settings: pcmBuffer.format.settings,
                        commonFormat: .pcmFormatInt16,
                        interleaved: false)
                }
                try output?.write(from: pcmBuffer)
            } catch {
                print("error")
            }
        }
    }
    print("return")
    return fileURL!
}

预期输出:

Speech file does not exist at file:///var/mobile/Containers/Data/Application/A5E69CE0-FB83-481C-89B2-26C802446A03/Documents/myspeech.caf
callback
return
Speech file exists at file:///var/mobile/Containers/Data/Application/A5E69CE0-FB83-481C-89B2-26C802446A03/Documents/myspeech.caf

实际输出:

Speech file does not exist at file:///var/mobile/Containers/Data/Application/A5E69CE0-FB83-481C-89B2-26C802446A03/Documents/myspeech.caf
return
no file exists at file:///var/mobile/Containers/Data/Application/A5E69CE0-FB83-481C-89B2-26C802446A03/Documents/myspeech.caf

特别注意callback永远不会运行,那里出了点问题。

标签: iosswiftswiftui

解决方案


let fileName = "Content.txt";
let fileManger = FileManager.default;
let doumentDirectoryPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString;
let filePath = doumentDirectoryPath.appendingPathComponent(fileName);

if fileManger.fileExists(atPath: filePath) {
    let url = URL(fileURLWithPath: filePath);
    //your file is in url
}else{
    // file not exist
}

推荐阅读