Speech-to-Text
UIViewController.h
#import <UIKit/UIKit.h>
#import <Speech/Speech.h>
#import "GlobalAssistant.h"
@interface FreeTextView : UIViewController <SFSpeechRecognizerDelegate>
{
__weak IBOutlet UIImageView *animationImageView;
SFSpeechRecognizer *speechRecognizer;
SFSpeechAudioBufferRecognitionRequest *recognitionRequest;
SFSpeechRecognitionTask *recognitionTask;
SFSpeechURLRecognitionRequest *urlRequest;
// Record speech using audio Engine
AVAudioInputNode *inputNode;
AVAudioEngine *audioEngine;
}
// --------- Initialize GlobalAssistant
@property (strong , nonatomic) GlobalAssistant *globalObject ;
@property(strong, nonatomic)IBOutlet UITextView *txtAnswer ;
- (IBAction)microPhoneTapped:(id)sender ;
@end
UIViewController.m
#import "FreeTextView.h"
#import "UIImage+animatedGIF.h"
@interface FreeTextView ()
@end
@implementation FreeTextView
@synthesize btnSpeech, txtAnswer ;
@synthesize globalObject ;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// --------- Initialize GlobalAssistant
globalObject = [[GlobalAssistant alloc] init] ;
}
#pragma mark - Button Click (Speech Recognization)
- (IBAction)microPhoneTapped:(id)sender {
if (audioEngine.isRunning) {
[globalObject showActivityIndicator];
recognitionTask =[speechRecognizer recognitionTaskWithRequest:recognitionRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
[self->globalObject removeActivityIndicator];
if (result != nil) {
NSString *transcriptText = result.bestTranscription.formattedString;
self->txtAnswer.text = transcriptText;
}
else {
[self->audioEngine stop];;
self->recognitionTask = nil;
self->recognitionRequest = nil;
}
}];
// make sure you release tap on bus else your app will crash the second time you record.
[inputNode removeTapOnBus:0];
[audioEngine stop];
[recognitionRequest endAudio];
[btnSpeech setBackgroundImage:[UIImage imageNamed:@"mic"] forState:UIControlStateNormal];
animationImageView.hidden = YES;
}
else {
[self startRecording];
}
}
#pragma mark - Voice SCAN
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
audioEngine = [[AVAudioEngine alloc] init];
NSLocale *local =[[NSLocale alloc] initWithLocaleIdentifier:@"en-US"];
speechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:local];
// for (NSLocale *locate in [SFSpeechRecognizer supportedLocales]) {
// NSLog(@"%@", [locate localizedStringForCountryCode:locate.countryCode]);
// }
// Check Authorization Status
// Make sure you add "Privacy - Microphone Usage Description" key and reason in Info.plist to request micro permison
// And "NSSpeechRecognitionUsageDescription" key for requesting Speech recognize permison
[SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
dispatch_async(dispatch_get_main_queue(), ^{
switch (status) {
case SFSpeechRecognizerAuthorizationStatusAuthorized: {
self->btnSpeech.enabled = YES;
break;
}
case SFSpeechRecognizerAuthorizationStatusDenied: {
self->btnSpeech.enabled = NO;
// resultTextView.text = @"User denied access to speech recognition";
}
case SFSpeechRecognizerAuthorizationStatusRestricted: {
self->btnSpeech.enabled = NO;
// resultTextView.text = @"User denied access to speech recognition";
}
case SFSpeechRecognizerAuthorizationStatusNotDetermined: {
self->btnSpeech.enabled = NO;
// resultTextView.text = @"User denied access to speech recognition";
}
}
});
}];
}
// Transcript from a file
- (void)transcriptExampleFromAFile {
NSURL *url = [[NSBundle mainBundle] URLForResource:@"checkFile" withExtension:@"m4a"];
urlRequest = [[SFSpeechURLRecognitionRequest alloc] initWithURL:url];
recognitionTask = [speechRecognizer recognitionTaskWithRequest:urlRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
if (result != nil) {
NSString *text = result.bestTranscription.formattedString;
self->txtAnswer.text = text;
}
else {
NSLog(@"Error, %@", error.description);
}
}];
}
// recording
- (void)startRecording {
NSURL *url = [[NSBundle mainBundle] URLForResource:@"micon" withExtension:@"gif"];
animationImageView.image = [UIImage animatedImageWithAnimatedGIFURL:url];
animationImageView.hidden = NO;
[btnSpeech setBackgroundImage:[UIImage imageNamed:@"micon"] forState:UIControlStateNormal];
if (recognitionTask) {
[recognitionTask cancel];
recognitionTask = nil;
}
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryRecord mode:AVAudioSessionModeMeasurement options:AVAudioSessionCategoryOptionDefaultToSpeaker error:nil];
[session setActive:TRUE withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
inputNode = audioEngine.inputNode;
recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
recognitionRequest.shouldReportPartialResults = NO;
// recognitionRequest.detectMultipleUtterances = YES;
AVAudioFormat *format = [inputNode outputFormatForBus:0];
[inputNode installTapOnBus:0 bufferSize:1024 format:format block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
[self->recognitionRequest appendAudioPCMBuffer:buffer];
}];
[audioEngine prepare];
NSError *error1;
[audioEngine startAndReturnError:&error1];
NSLog(@"%@", error1.description);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
//***************** OR
2nd Method (Word Detect)
//*****************
#pragma mark - Button Click (Speech Recognization)
- (IBAction)microPhoneTapped:(id)sender {
if (audioEngine.isRunning) {
[audioEngine stop];
[recognitionRequest endAudio];
[btnSpeech setBackgroundImage:[UIImage imageNamed:@"mic"] forState:UIControlStateNormal];
animationImageView.hidden = YES;
} else {
[self startRecording];
}
}
#pragma mark - Voice SCAN
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
audioEngine = [[AVAudioEngine alloc] init];
NSLocale *local =[[NSLocale alloc] initWithLocaleIdentifier:@"en-US"];
speechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:local];
// for (NSLocale *locate in [SFSpeechRecognizer supportedLocales]) {
// NSLog(@"%@", [locate localizedStringForCountryCode:locate.countryCode]);
// }
// Check Authorization Status
// Make sure you add "Privacy - Microphone Usage Description" key and reason in Info.plist to request micro permison
// And "NSSpeechRecognitionUsageDescription" key for requesting Speech recognize permison
[SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
dispatch_async(dispatch_get_main_queue(), ^{
switch (status) {
case SFSpeechRecognizerAuthorizationStatusAuthorized: {
self->btnSpeech.enabled = YES;
break;
}
case SFSpeechRecognizerAuthorizationStatusDenied: {
self->btnSpeech.enabled = NO;
// resultTextView.text = @"User denied access to speech recognition";
}
case SFSpeechRecognizerAuthorizationStatusRestricted: {
self->btnSpeech.enabled = NO;
// resultTextView.text = @"User denied access to speech recognition";
}
case SFSpeechRecognizerAuthorizationStatusNotDetermined: {
self->btnSpeech.enabled = NO;
// resultTextView.text = @"User denied access to speech recognition";
}
}
});
}];
}
// recording
- (void)startRecording {
NSURL *url = [[NSBundle mainBundle] URLForResource:@"micon" withExtension:@"gif"];
animationImageView.image = [UIImage animatedImageWithAnimatedGIFURL:url];
animationImageView.hidden = NO;
[btnSpeech setBackgroundImage:[UIImage imageNamed:@"micon"] forState:UIControlStateNormal];
// Initialize the AVAudioEngine
audioEngine = [[AVAudioEngine alloc] init];
// Make sure there's not a recognition task already running
if (recognitionTask) {
[recognitionTask cancel];
recognitionTask = nil;
}
// Starts an AVAudio Session
NSError *error;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:&error];
[audioSession setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
// Starts a recognition process, in the block it logs the input or stops the audio
// process if there's an error.
recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
AVAudioInputNode *inputNode = audioEngine.inputNode;
recognitionRequest.shouldReportPartialResults = YES;
recognitionTask = [speechRecognizer recognitionTaskWithRequest:recognitionRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
BOOL isFinal = NO;
if (result) {
// Whatever you say in the microphone after pressing the button should be being logged
// in the console.
NSLog(@"RESULT:%@",result.bestTranscription.formattedString);
isFinal = !result.isFinal;
self->txtAnswer.text = result.bestTranscription.formattedString ;
self->lblPlaceHolder.hidden = YES ;
}
if (error) {
[self->audioEngine stop];
[inputNode removeTapOnBus:0];
self->recognitionRequest = nil;
self->recognitionTask = nil;
}
}];
// Sets the recording format
AVAudioFormat *recordingFormat = [inputNode outputFormatForBus:0];
[inputNode installTapOnBus:0 bufferSize:1024 format:recordingFormat block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
[self->recognitionRequest appendAudioPCMBuffer:buffer];
}];
// Starts the audio engine, i.e. it starts listening.
[audioEngine prepare];
[audioEngine startAndReturnError:&error];
NSLog(@"Say Something, I'm listening");
}