如何使用 iOS 7 的 AVSpeechSynthesizer 製作有聲書(4)
控制:我們必須學會控制
大師尤達(電影《星球大戰》)曾有言:關鍵在於控制。這本故事書是一個詞一個詞地念出來的,我準備為它增加兩個按鈕,這樣我們就可以實時地調整語音合成時的音高和語速。
仍然是 RWTPageViewController.m,在nextSpeechIndex 屬性後宣告下列屬性:
@property (nonatomic, assign) float currentPitchMultiplier; @property (nonatomic, assign) float currentRate; |
在 gotoPreviousPage:方法後增加如下方法:
- (void)lowerPitch { if (self.currentPitchMultiplier > 0.5f) { self.currentPitchMultiplier = MAX(self.currentPitchMultiplier * 0.8f, 0.5f); } } - (void)raisePitch { if (self.currentPitchMultiplier < 2.0f) { self.currentPitchMultiplier = MIN(self.currentPitchMultiplier * 1.2f, 2.0f); } } - (void)lowerRate { if (self.currentRate > AVSpeechUtteranceMinimumSpeechRate) { self.currentRate = MAX(self.currentRate * 0.8f, AVSpeechUtteranceMinimumSpeechRate); } } - (void)raiseRate { if (self.currentRate < AVSpeechUtteranceMaximumSpeechRate) { self.currentRate = } } -(void) speakAgain { if (self.nextSpeechIndex == [[self currentPage].utterances count]) { self.nextSpeechIndex = 0; [self speakNextUtterance]; } } |
這些方法將和語音控制面板上的按鈕相連線。
- lowerPitch: 和 raisePitch: 方法用於降低和提高音高,每次都會在原有基礎上減低或增加20%,但該值會限定在(0.5-2.0)之間。
- lowerRate: 和 raiseRate 方法用於降低和提高朗讀的語速,每次會在原有基礎上+/- 20%,總體範圍限定在 AVSpeechUtteranceMinimumSpeechRate 和 AVSpeechUtteranceMaximumSpeechRate 之間。
- speakAgain: 重置當前語句的索引值,並再次顯示相應的文字內容。
建立按鈕,然後在 raiseRate 方法後加入下列方法:
-(void) addSpeechControlWithFrame: (CGRect) frame title:(NSString *) title action:(SEL) selector { UIButton *controlButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; controlButton.frame = frame; controlButton.backgroundColor = [UIColor colorWithWhite:0.9f alpha:1.0f]; [controlButton setTitle:title forState:UIControlStateNormal]; [controlButton addTarget:self action:selector forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:controlButton]; } - (void)addSpeechControls { [self addSpeechControlWithFrame:CGRectMake(52, 485, 150, 50) title:@"Lower Pitch" action:@selector(lowerPitch)]; [self addSpeechControlWithFrame:CGRectMake(222, 485, 150, 50) title:@"Raise Pitch" action:@selector(raisePitch)]; [self addSpeechControlWithFrame:CGRectMake(422, 485, 150, 50) title:@"Lower Rate" action:@selector(lowerRate)]; [self addSpeechControlWithFrame:CGRectMake(592, 485, 150, 50) title:@"Raise Rate" action:@selector(raiseRate)]; [self addSpeechControlWithFrame:CGRectMake(506, 555, 150, 50) title:@"Speak Again" action:@selector(speakAgain)]; } |
addSpeechControlWithFrame:方法是一個便利方法,用於在檢視中新增一個按鈕並將其與相應的方法連線起來,這樣就可以通過按鈕來調整語音。
注意:也可以在 Main.storyboard 中建立按鈕並繫結他們的action 到 RWTPageViewController。這樣更容易,效率也更高。
在 viewDidLoad 的 [self startSpeaking] 方法之前加入:
// 1 self.currentPitchMultiplier = 1.0f; self.currentRate = AVSpeechUtteranceDefaultSpeechRate; // 2 [self addSpeechControls]; |
註釋“1”處設定預設的語音屬性,註釋“2”處則新增語音控制按鈕。
最後,修改 speakNextUtterance 方法:
- (void)speakNextUtterance { if (self.nextSpeechIndex < [[self currentPage].utterances count]) { AVSpeechUtterance *utterance = [[self currentPage].utterances objectAtIndex:self.nextSpeechIndex]; self.nextSpeechIndex += 1; // 1 utterance.pitchMultiplier = self.currentPitchMultiplier; // 2 utterance.rate = self.currentRate; [self.synthesizer speakUtterance:utterance]; } } |
如果你點選了 lower/raise 按鈕,則新設定的值將在下一句朗讀中得到應用。
編譯執行。如下圖所示:
觸控或點選這些按鈕,然後注意發音的變化。尤達確實很厲害,哪怕你不是傑迪也可以成為大師(AVSpeechSynthesizer 方面的)。
結尾
希望本文能成為激發你開發自己的有聲書的動力。如果你想知道更多的關於如何對合成語音進行調優的技巧,請看下面:
最佳有聲書WhirlySquirrelly.plist競賽
說明:請嘗試進一步調優 WhirlySquirrelly.plist,並上傳至論壇或者本文留言裡。我們會評出其中的優勝者,並在評論中加以褒揚。
允許使用者選擇圖書
說明: 新增一個“Choose Book” 按鈕,並在 UIPopoverController中顯示一個可選的圖書列表。當用戶選擇某本圖書,在 RWTPageViewController 中重置 book 物件並顯示新書。
從 Web 上下載圖書
說明:將書籍以 plist 格式儲存在 web伺服器或者提供類似 AWS S3 或者 Heroku 的服務。伺服器先要提供一個 url列表,列出所有圖書,然後再提供一個可以下載某本書的服務。在前一個功能中,將圖書的連結新增進去。
唸到詞高亮顯示
提示: 使用AVSpeechSynthesizerDelegate 委託中的方法
在 speechSynthesizer:didStartSpeechUtterance:方法中,高亮指定的 utterance。
在 speechSynthesizer:didFinishSpeechUtterance:方法中,將高亮的 utterance 去高亮。你可以用 pageTextLable 的 attributedText 屬性,通過NSAttributedString 設定不同的背景色和字型屬性以實現加亮效果。
在第一頁顯示書名
Addthe Ability to Display a Title Page Before All Other Pages
說明:在 RWTPageViewController 之前加入額外的 viewController,並設定 Main.storyboard 屬性已啟用新的viewcontroller。將兩個 ViewController 用一個 UINavigationController 管理起來。 為此,你可以修改 Page 類的設計,並分為有聲的 Page 和無聲的 Page,然後修改 RWTPageViewController 讓它能夠處理這兩種不同的Page。