如何使用 iOS 7 的 AVSpeechSynthesizer 制作有声书(2)

切分语句

软件工程的一条定律是数据和代码分离。这样做会使代码更易于测试,即使输入的数据发生改变,你的代码也能够允许。甚至于,程序能在运行中实时下载新的数据。如果程序能在运行中下载新书岂不是更好?

你现在用的书是用 Book.testBook 方法中的代码创建的。接下来我们将书改为以文件形式存储,读取的时候则通过Plist 文件来读取。

打开 SupportingFiles\WhirlySquirrelly.plist ,其内容如下:

你还可以通过右键->“Open As\Source Code”来查看其源码:


<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plistversion="1.0">

<dict>

<key>bookPages</key>

<array>

<!-- First page -->

<dict>

<key>backgroundImage</key>

<string>PageBackgroundImage.jpg</string>

<key>utterances</key>

<array>

<dict>

<key>utteranceProperties</key>

<dict>

<key>pitchMultiplier</key>

<real>1</real>

<key>rate</key>

<real>1.2</real>

</dict>

<key>utteranceString</key>

<string>Whisky,</string>

</dict>

...

</array>

</dict>

<!-- Second page -->

<dict>

<key>backgroundImage</key>

<string>PageBackgroundImage.jpg</string>

<key>utterances</key>

<array>

<dict>

<key>utteranceProperties</key>

<dict>

 

<key>pitchMultiplier</key>

<real>1.2</real>

<key>rate</key>

<real>1.3</real>

</dict>

<key>utteranceString</key>

<string>Whirly,</string>

</dict>

...

</array>

</dict>

</array>

</dict>

</plist>

它的数据结构用一个抽象的表示则如下图所示(这里{}代表字典,[]代表数组):

Book {

bookPages => [

{FirstPage

backgroundImage => "Name ofbackground image file",

utterances => [

{ utteranceString     => "what to say first",

utteranceProperties => { how to say it }

},

{ utteranceString     => "what to say next",

utteranceProperties => { how to say it }

}

]

},

{SecondPage

backgroundImage => "Name ofbackground image file",

utterances => [

{ utteranceString     => "what to say last",

utteranceProperties => { how to say it }

}

]

}

]

}

感谢伟大的 ASCII 艺术!:]

WhirlySquirrelly.plist将文本按照一个单词一个utterance 的方式进行切。这样做的好处是你可以控制每一个词的音高(高音、低音)和语速(快、慢)。之所以合成的语音太机械,就像一部上世纪50年代的低劣科幻电影,是因为他的发音太呆板了。为了使合成语音更接近于人,必须控制音高和语速,使其更富于变化。

解析plist

我们需要将WhirlySquirrelly 解析成 RWTBook 对象。打开RWTBook.h 在 bookWithPages:方法之后加入:


+ (instancetype)bookWithContentsOfFile:(NSString*)path;

这个方法会读取 WhirlySquirrelly.plist文件,然后根据文件内容返回一个  RWTBook实例。

打开 RWTBook.mand 在 #import "RWTPage.h" 下面加入:


#pragma mark -

External Constants   NSString* const RWTBookAttributesKeyBookPages = @"bookPages";

这个常量是一个键名,用于从 plist 文件中检索图书的全部页数据。

RWTBook.m 在@end 之前加入:


#pragma mark - Private

+ (instancetype)bookWithContentsOfFile:(NSString*)path {

// 1

NSDictionary *bookAttributes = [NSDictionary dictionaryWithContentsOfFile:path];

if (!bookAttributes) {

return nil;

}

// 2

NSMutableArray *pages = [NSMutableArray arrayWithCapacity:2];

for (NSDictionary *pageAttributes in [bookAttributes objectForKey:RWTBookAttributesKeyBookPages]) {

RWTPage *page = [RWTPage pageWithAttributes:pageAttributes];

if (page) {

[pages addObject:page];

}

}

// 3

return [self bookWithPages:pages];

}

以上代码负责以下工作:

  1. 从给定的文件中读取并初始化了一个 NSDictionary 对象。这个文件就是WhirlySquirrelly.plist。
  2. 遍历字典中的 bookPages 数组,将数组中每个元素解析为 Page 对象。
  3. 通过 bookWithPages 方法返回一个全新的 book 对象。

打开 RWTPageViewController.mand navigate ,在 viewDidLoad找到这一行:


[self setupBook:[RWTBook testBook]];

将其替换为:


NSString *path = [[NSBundle mainBundle] pathForResource:@"WhirlySquirrelly" ofType:@"plist"];

[self setupBook:[RWTBook bookWithContentsOfFile:path]];

这段代码将找到 WhirlySquirrelly.plist 的全路径,然后调用 bookWithContentsOfFile:创建 book 对象。

打开 RWTPage.m 在#import "RWTPage.h"之后加入:


@import AVFoundation;

现在你可以在文件中引用 AVSpeechUtterance 了。

在 RWTPageAttributesKeyBackgroundImage声明之后添加如下声明:


NSString* const RWTUtteranceAttributesKeyUtteranceString = @"utteranceString";

NSString* const RWTUtteranceAttributesKeyUtteranceProperties = @"utteranceProperties";

这些常量都是用于从 plist 中访问每一个AVSpeechUtterance 的属性时要用到的。将

pageWithAttributes:方法修改为:


+ (instancetype)pageWithAttributes:(NSDictionary*)attributes {

RWTPage *page = [[RWTPage alloc] init];

if ([[attributes objectForKey:RWTPageAttributesKeyUtterances] isKindOfClass:[NSString class]]) {

// 1

page.displayText = [attributes objectForKey:RWTPageAttributesKeyUtterances];

page.backgroundImage = [attributes objectForKey:RWTPageAttributesKeyBackgroundImage];

} else if ([[attributes objectForKey:RWTPageAttributesKeyUtterances] isKindOfClass:[NSArray class]]) {

// 2

NSMutableArray *utterances = [NSMutableArray arrayWithCapacity:31];

NSMutableString *displayText = [NSMutableString stringWithCapacity:101];

// 3

for (NSDictionary *utteranceAttributes in [attributes objectForKey:RWTPageAttributesKeyUtterances]) {

// 4

NSString *utteranceString =                  [utteranceAttributes objectForKey:RWTUtteranceAttributesKeyUtteranceString];

NSDictionary *utteranceProperties =                      [utteranceAttributes objectForKey:RWTUtteranceAttributesKeyUtteranceProperties];

// 5

AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:utteranceString];

// 6

[utterance setValuesForKeysWithDictionary:utteranceProperties];

if (utterance) {

// 7

[utterances addObject:utterance];

[displayText appendString:utteranceString];

}

}

// 8

page.displayText = displayText;

page.backgroundImage = [UIImage imageNamed:[attributes objectForKey:RWTPageAttributesKeyBackgroundImage]];

}

return page;

}

这段代码负责:

  1. 处理 RWTBook.testBook 调用情况,这种情况下,page 的 utterances 属性是一个 NSString。设置 displayText 和 backgroundImage 属性。
  2. 处理 book 数据来自 WhirlySquirrelly.plist  的情况,这种情况下,page 的 utterances 是一个 NSArray 。将所有 utterances 和 display Text 合并。
  3. 遍历 page 中的每个 utterances 。
  4. 读取每个 utterances 的 utteranceString 和 utteranceProperties。
  5. 创建一个 AVSpeechUtterance 用于朗读 utteranceString。
  6. 通过键值编码(KVC)来修改 AVSpeechUtterance 实例属性。虽然苹果未在文档中说明,但可以调用 AVSpeechUtterance 的 setValuesForKeysWithDictionary:方法来设置所有 utteranceProtperties 属性。也就是说,你可以向 plist 中添加新的 utterance 属性,而不需要调用其 setter 方法,setValuesForKeysWithDictionary:方法会自动处理新属性。当然,在 AVSpeechUtterance 中相应的属性必须存在而且是可写的。
  7. 累加 utterance 并显示文本。
  8. 设置要显示的文本和背景图片。

编译运行,听听都在说些什么。

如何使用 iOS 7 的 AVSpeechSynthesizer 制作有声书(2)

时间: 2024-10-11 00:12:28

如何使用 iOS 7 的 AVSpeechSynthesizer 制作有声书(2)的相关文章

如何使用 iOS 7 的 AVSpeechSynthesizer 制作有声书(1)

原文: http://www.raywenderlich.com/64623/make-narrated-book-using-avspeechsynthesizer-ios-7 随着 PageViewController 的引入,苹果让开发者们制作图书类app 更加轻松.不幸的是,对于生活在朝九晚五繁忙节奏中的人们来说,阅读也是一件奢侈的事情.为什么你不能在读一本小说的同时做其他事情呢? 在 Siri 刚开始出现的时候,苹果曾经用复杂的动态文本阅读将开发者拒之门外,但当iOS7 发布的时候,苹

如何使用 iOS 7 的 AVSpeechSynthesizer 制作有声书(3)

plist 中的每一页 utteranceSting 我们都创建了一个RWTPage.displayText.因此,每页的文本会一次性地显示出来. 由于 You've constructedeach RWTPage.displayTextfrom the combined utteranceStringsfor the page in the plist. So, your page view displays the entire page's text.However, remember t

如何使用 iOS 7 的 AVSpeechSynthesizer 制作有声书(4)

控制:我们必须学会控制 大师尤达(电影<星球大战>)曾有言:关键在于控制.这本故事书是一个词一个词地念出来的,我准备为它增加两个按钮,这样我们就可以实时地调整语音合成时的音高和语速. 仍然是 RWTPageViewController.m,在nextSpeechIndex 属性后声明下列属性: @property (nonatomic, assign) float currentPitchMultiplier; @property (nonatomic, assign) float curre

怎样使用 iOS 7 的 AVSpeechSynthesizer 制作有声书(2)

切分语句 软件project的一条定律是数据和代码分离.这样做会使代码更易于測试,即使输入的数据发生改变,你的代码也能够同意.甚至于,程序能在执行中实时下载新的数据.假设程序能在执行中下载新书岂不是更好? 你如今用的书是用 Book.testBook 方法中的代码创建的.接下来我们将书改为以文件形式存储,读取的时候则通过Plist 文件来读取. 打开 SupportingFiles\WhirlySquirrelly.plist ,其内容例如以下: 你还能够通过右键->"Open As\So

如何使用 iOS 7 的 AVSpeechSynthesizer 国家有声读物(4)

控制:我们一定要学会控制 尤达大师(电影<星球大战>)有话:的关键在于控制.这本故事书是一个字一个字读出来,我愿意为它添加两个button,音调和语速,以便我们能够调整语音合成实时的时候. 还是 RWTPageViewController.m,在nextSpeechIndex 属性后声明下列属性: @property (nonatomic, assign) float currentPitchMultiplier; @property (nonatomic, assign) float cur

iOS 推送证书制作(JAVA/PHP)

iOS 推送证书制作(JAVA/PHP) 在使用Java或者PHP制作iOS推送服务器的时候,需要自己从开发者网站上导出的aps_developer_identity证书和Apple Development Push Services证书进行合成,生成可以供Java使用的p12证书或供PHP使用的pem证书.aps_developer_identity证书和Apple Development Push Services证书的申请过程可以参考:http://www.cnblogs.com/hubj

AFNetworking是一个为 iOS 和 Mac OSX 制作的令人愉快的网络库

AFNetworking是一个为 iOS 和 Mac OSX 制作的令人愉快的网络库,它建立在URL 装载系统框架的顶层,内置在Cocoa里,扩展了强有力的高级网络抽象.它的模块架构被良好的设计,拥有丰富的功能,因此,使用起来,必定赏心悦目. @介绍 1.支持HTTP请求和基于REST的网络服务(包括GET.POST. PUT.DELETE等) 2.支持ARC 3.要求iOS 5.0及以上版本 4.UIKit扩展@配置1.下载AFNetworking,将2个文件夹:AFNetworking和UI

iOS 推送证书制作 (JAVA/PHP)

// aps_development.cer 转化成pem openssl x509 -in aps_development.cer -inform der -out PushChatCert.pem // p12 转化成pem openssl pkcs12 -nocerts -out PushChatKey.pem -in Push.p12 // Java服务器所需的证书为p12格式 openssl pkcs12 -export -in PushChatCert.pem -inkey Push

为什么人们爱听有声书?

今日导读 都说"一千个人心中就有一千个哈姆雷特",那么试问,在音频对白中听到的哈姆雷特,相比在舞台上.荧幕上看到的哈姆雷特,哪一种给你留下的印象会更深刻呢?单纯的听觉享受和多维的视觉呈现,哪项更重要?今天这篇来自<卫报>的新闻或许能给你不一样的启发. 新闻正文 ? Listen and weep: 'Audiobooks outdo films in emotional engagement' 闻者流泪(流血):有声书比电影更能调动你的感情 注:engagement:约会;