Я пытаюсь сгенерировать файлы .aiff с помощью NSSpeechSynthesizer.startSpeakingString(), и я использую GCd с помощью последовательной очереди, так как NSSpeechSynthesizer берет строку и создает файл aiff по указанному адресу NSURL. Я использовал стандарт для метода loop для списка строк в [String: [String]], но это создает некоторые файлы с 0 байтами.swift OSX: серийный генератор файлов с использованием GCD
Вот функция для генерации речи:
func createSpeech(type: String, name: String) {
if !NSFileManager.defaultManager().fileExistsAtPath("\(dataPath)\(type)/\(name)/\(name).aiff"){
do{
try NSFileManager().createDirectoryAtPath("\(dataPath)\(type)/\(name)/", withIntermediateDirectories: true, attributes: nil)
let URL = NSURL(fileURLWithPath: "\(dataPath)\(type)/\(name)/\(name).aiff")
print("Attempting to save speech \(name).aiff")
self.synth.startSpeakingString(name, toURL: URL)
}catch{
print("error occured")
}
}
}
А вот функция, которая пересекает словарь для создания файлов:
for key in self.nodeLibrary.keys{
dispatch_sync(GlobalBackgroundQueue){
let type = self.nodeLibrary[key]?.0
let name = key.componentsSeparatedByString("_")[0]
if !speechCheck.contains(name){
mixer.createSpeech(type!, name: name)
}
}
}
globalBackgroundQueue является псевдонимом очереди НОД звоните _T для удобства чтения.
Обычная программа работает нормально, создает папки и подпапки, как требуется другой внешней функцией, затем синтезирует речь, но в моем случае я всегда получаю один или несколько, которые не загружаются должным образом, давая 0 байт или слишком малое количество байтов что делает файл непригодным.
Я прочитал следующую запись и используют эти методы НОД на некоторое время, но я не уверен, где я неправильно здесь:
http://www.raywenderlich.com/60749/grand-central-dispatch-in-depth-part-1
Любая помощь очень ценится как обычно
Редактировать: Обновлено с завершением закрытия и обнаружено, возможно, ошибка
Я создал функцию закрытия, как показано ниже, и использую ее в другом вспомогательном методе, который проверяет любые ошибки, такие как sourceFile.length, равный 0 после загрузки. Тем не менее, все файлы имеют длину 0, что невозможно, так как я проверял свойства звука каждого файла с помощью команды свойства finder + i.
func synthesise(type: String, name: String, completion: (success: Bool)->()) {
if !NSFileManager.defaultManager().fileExistsAtPath("\(dataPath)\(type)/\(name)/\(name).aiff"){
do{
try NSFileManager().createDirectoryAtPath("\(dataPath)\(type)/\(name)/", withIntermediateDirectories: true, attributes: nil)
let URL = NSURL(fileURLWithPath: "\(dataPath)\(type)/\(name)/\(name).aiff")
let success = self.synth.startSpeakingString(name, toURL: URL)
completion(success: success)
}catch{
print("error occured")
}
}
}
func loadSpeech(type: String, name: String){
synthesise(type, name: name, completion: {(success: Bool)->Void in
if success{
print("File \(name) created successfully with return \(self.synthSuccess), checking file integrity")
let URL = NSURL(fileURLWithPath: "\(self.dataPath)\(type)/\(name)/\(name).aiff")
do{
let source = try AVAudioFile(forReading: URL)
print("File has length: \(source.)")
}catch{
print("error loading file")
}
}else{
print("creation unsuccessful, trying again")
self.loadSpeech(type, name: name)
}
})
}
файлы генерируются с их папки и как метод startSpeakingString-> Bool и функции делегата у меня в классе, который обновляет synthSuccess свойство показывать верно. Поэтому я загружаю AVAudioFile, чтобы проверить его длину. Все длины файлов равны 0. Какие они не за исключением одного.
Когда я говорю об ошибке, это из другой части приложения, где я загружаю AVAudioEngine и начинаю загрузку буферов с аргументом frameCount, установленным в sourceAudioFile.length, который дает диагностическую ошибку, но сейчас это вне контекста.
Есть еще вопросы в отредактированный код: 1 В вашем методе 'synhesize' вы не завершаете _when_ асинхронная задача была завершена. Вместо этого вы немедленно завершите его после того, как вы запустили асинхронную задачу. Исправлено: вам нужно использовать _delegate_ 'NSSpeechSynthesizerDelegate', чтобы получить уведомление _when_ задача завершена. Затем и только тогда вызовите обработчик завершения. Во-вторых, вам необходимо убедиться, что обработчик завершения в конечном итоге будет вызван. То есть, это ДОЛЖНО быть вызвано в конечном итоге. В вашем методе 'synhesize' вы не выполняете это требование. – CouchDeveloper
2. 'loadSpeech' не работает так, как вы ожидаете. Из-за 1. он не будет вызван, когда синтез завершится неудачей. 3. Вам по-прежнему нужен способ обеспечения последовательного вызова нескольких входов.У вашего метода 'loadSpeech' есть уже базовая структура для выполнения этого. Создайте новый с параметром массива входов и обработчиком завершения. Внутренняя функция имеет inout параметр 'Generator' и обработчик завершения. Вызовите 'gen.next' во внутренней функции, чтобы получить следующий элемент в массиве. Когда задача завершена, вызовите внутреннюю функцию, передающую ей генератор. – CouchDeveloper
Да, у меня есть как didFinishSpeaking, так и didEncounterError в моем файле класса. Я сделал 3 разных подхода, один с использованием блоков, другой с GCD и простой, проверяя свойство, которое я называю finalSpeak: Bool. Нет. Цикл while продолжается вечно. Однако я также протестировал один startSpeakingString без toURL, и сообщения печатаются на консоль. Когда я использую toURL, сообщение печатает, но файл поврежден, хотя сообщение об ошибке не распечатывается (которое я установил как print («\ (message) является ошибкой»). Я вижу, что другие пользователи имеют такую же проблему с поврежденными файлами NSSpeechSynthesizer, – triple7