Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading NSSpeechSynthesizer保存到URL_Multithreading_Swift_Macos_Grand Central Dispatch_Text To Speech - Fatal编程技术网

Multithreading NSSpeechSynthesizer保存到URL

Multithreading NSSpeechSynthesizer保存到URL,multithreading,swift,macos,grand-central-dispatch,text-to-speech,Multithreading,Swift,Macos,Grand Central Dispatch,Text To Speech,我正在创建一个MacOS应用程序,它从制表符分隔的文本文件生成对话框文件。文本文件已格式化(输出文件名)[tab](要与该文件对话的文本)。我让程序在主线程中完美运行,但这当然会阻塞UI。当我将应用程序的内容移动到用户启动的线程时,我取消了对UI的阻止,但现在它偶尔会随机地从说话者那里说出一行,而不是对文件。文件仍在创建中,但持续时间为零。如果脚本包含1000行,它可能会完美地完成整个过程,或者它可能会“说出”其中的10行或更多行。几乎每次都是不同的台词 这是与文件对话的代码: // Set U

我正在创建一个MacOS应用程序,它从制表符分隔的文本文件生成对话框文件。文本文件已格式化(输出文件名)[tab](要与该文件对话的文本)。我让程序在主线程中完美运行,但这当然会阻塞UI。当我将应用程序的内容移动到用户启动的线程时,我取消了对UI的阻止,但现在它偶尔会随机地从说话者那里说出一行,而不是对文件。文件仍在创建中,但持续时间为零。如果脚本包含1000行,它可能会完美地完成整个过程,或者它可能会“说出”其中的10行或更多行。几乎每次都是不同的台词

这是与文件对话的代码:

// Set URL to save file to disk
if let speechFileURL = NSURL(string: speechFilePath) {
    speechSynth.startSpeakingString(spokenText, toURL: speechFileURL)  // Speak to file
}
else {
    dialogAlert("Invalid File: ", text: speechFileName)
}

while(NSSpeechSynthesizer.isAnyApplicationSpeaking() == true) {
    if self.gUserClickedStop {
        speechSynth.stopSpeaking()
        self.gIsSpeaking = false
        break
    }
}
这是对解析脚本并生成语音文件的函数的调用:

dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) { [unowned self] in
    self.parseTheScript()
}
如上所述,调用parseTheScript()而不在Grand Central Dispatch调用中对其进行包装可以使其完美工作,除了阻塞问题

我不熟悉Swift编程和多线程编程的概念,所以我肯定我做错了什么,但我很难解决这个问题

提前感谢您的帮助

编辑以添加

这是解析文本文件并生成对话框文件的整个函数:

    // This opens the text file and generates the spoken audio files
func parseTheScript() {
    let filemgr = NSFileManager.defaultManager()
    print("Chosen path: \(scriptFileTextField.stringValue)")   // debug
    if filemgr.fileExistsAtPath(scriptFileTextField.stringValue) {
        print("File exists")
        do {
            outputFilename.stringValue = ""
            scriptToSpeak.stringValue = ""
            outputFilename.hidden = false
            scriptToSpeak.hidden = false
            progressBar.minValue = 0
            progressBar.doubleValue = 0.0
            progressBar.hidden = false
            filenameLabel.hidden = false

            let text = try String(contentsOfFile: scriptFileTextField.stringValue, encoding: NSUTF8StringEncoding)
            let lines: [String] = text.componentsSeparatedByString("\n")
            var progressEndValue = Double(lines.count)
            progressBar.maxValue = progressEndValue

            let speechSynth = NSSpeechSynthesizer.init()
            let theVoice = gVoiceList[voiceListPopup.indexOfSelectedItem - 1]   // Not sure why it's off by one
            speechSynth.setVoice(theVoice)

            for line in lines {
                let thisLine: [String] = line.componentsSeparatedByString("\t") // Split the line at the tab character
                if (thisLine.count == 2) {                  // Did the line split into two parts?
                    let speechFileName = thisLine[0]
                    let spokenText = thisLine[1]
                    outputFilename.stringValue = speechFileName
                    scriptToSpeak.stringValue = spokenText
                    let speechFilePath = destinationFolderTextField.stringValue + speechFileName + ".aif"        // Build the path string for the output speech file
                    print("Filename: \(speechFilePath)")
                    print("SpokenText: \(spokenText)")

                    if(gSpeakToFile) {
                        // Set URL to save file to disk
                        if let speechFileURL = NSURL(string: speechFilePath) {
                            speechSynth.startSpeakingString(spokenText, toURL: speechFileURL)  // Speak to file
                        }
                        else {
                            dialogAlert("Invalid File: ", text: speechFileName)
                        }
                    }
                    else {
                        speechSynth.startSpeakingString(spokenText) // Speak to audio output
                    }

                    while(NSSpeechSynthesizer.isAnyApplicationSpeaking() == true) {
                        if self.gUserClickedStop {
                            speechSynth.stopSpeaking()
                            self.gIsSpeaking = false
                            break
                        }
                    }

                    progressBar.incrementBy(1.0)
                }
                if gUserClickedStop {
                    gUserClickedStop = false
                    gIsSpeaking = false
                    progressEndValue = 0
                    generateButton.title = "Start"
                    break
                }

            }
            gIsSpeaking = false
            progressBar.doubleValue = progressEndValue
            generateButton.title = "Start"
            filenameLabel.hidden = true
            outputFilename.stringValue = ""
            scriptToSpeak.stringValue = ""

        } catch let error as NSError {
            dialogAlert("Error:", text: String(error.localizedDescription))
            print("Error: \(error)")
        }
    } else {
        print("File does not exist")
    }

}

我也不认为它在主线程上运行得“完美”。您需要正确地实现委托方法,例如
speechSynthesizer:didFinishSpeaking:
,以便在
开始峰值字符串
完成时收到通知。您可以先查看一个示例,了解如何使用
NSSpeechSyntheziser
。无可否认,我一直将委托方法视为可选方法,因此我将进一步深入研究。我所说的“完美”,是指应用程序产生的结果正是我想要的结果。我认为您没有显示足够的代码。第一段代码何时执行?self.parseTheScript()的代码在哪里?我已经添加了整个parseTheScript函数。@MakerOfSound-你真的得到了NSSpeechSynthsizer的aiff(或任何东西)输出吗?我已经在我的一个应用程序中使用这个类有一段时间了,尽管我以前从未使用过toURL选项。当我调用它时,它返回的结果是一切都很好,实际上一切似乎都很好,只是没有生成任何文件。我认为它在主线程上运行也不是“完美的”。您需要正确地实现委托方法,例如
speechSynthesizer:didFinishSpeaking:
,以便在
开始峰值字符串
完成时收到通知。您可以先查看一个示例,了解如何使用
NSSpeechSyntheziser
。无可否认,我一直将委托方法视为可选方法,因此我将进一步深入研究。我所说的“完美”,是指应用程序产生的结果正是我想要的结果。我认为您没有显示足够的代码。第一段代码何时执行?self.parseTheScript()的代码在哪里?我已经添加了整个parseTheScript函数。@MakerOfSound-你真的得到了NSSpeechSynthsizer的aiff(或任何东西)输出吗?我已经在我的一个应用程序中使用这个类有一段时间了,尽管我以前从未使用过toURL选项。当我调用它时,它返回的结果是一切都很好,实际上似乎一切都很好,只是没有生成任何文件。