forked from holzschu/ios_system
-
Notifications
You must be signed in to change notification settings - Fork 0
/
say.m
137 lines (110 loc) · 3.37 KB
/
say.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <stdio.h>
#include "ios_system/ios_system.h"
#include "ios_error.h"
#include <getopt.h>
#import <AVFoundation/AVFoundation.h>
@interface SpeechSynthesizerDelegate : NSObject<AVSpeechSynthesizerDelegate>
- (void)wait;
@end
@implementation SpeechSynthesizerDelegate {
dispatch_semaphore_t _sema;
}
- (instancetype)init
{
self = [super init];
if (self) {
_sema = dispatch_semaphore_create(0);
}
return self;
}
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didCancelSpeechUtterance:(AVSpeechUtterance *)utterance {
dispatch_semaphore_signal(_sema);
}
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance {
dispatch_semaphore_signal(_sema);
}
- (void)wait {
dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER);
}
@end
int say_main(int argc, char *argv[]) {
optind = 1;
NSString *usage = @"Usage: say [-v voice] [-r rate] [-f file] [message]";
NSString *voice = nil;
NSString *file = nil;
NSNumber *rate = nil;
NSString *text = nil;
for (;;) {
int c = getopt(argc, argv, "v:f:r:");
if (c == -1) {
break;
}
switch (c) {
case 'v':
voice = @(optarg);
break;
case 'f':
file = @(optarg);
break;
case 'r':
rate = @([@(optarg) floatValue]);
break;
default:
printf("%s\n", usage.UTF8String);
return -1;//[self _exitWithCode:SSH_ERROR andMessage:[self _usage]];
}
}
if (optind < argc) {
NSMutableArray<NSString *> *words = [[NSMutableArray alloc] init];
for (int i = optind; i < argc; i++) {
[words addObject:@(argv[i])];
}
text = [words componentsJoinedByString:@" "];
}
AVSpeechSynthesisVoice *speechVoice = nil;
if ([voice isEqual:@"?"]) {
for (AVSpeechSynthesisVoice * v in AVSpeechSynthesisVoice.speechVoices) {
puts([NSString stringWithFormat:@"%-20s %@\n", v.name.UTF8String, v.language].UTF8String);
}
return 0;
} else if (voice) {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name BEGINSWITH[c] %@", voice];
speechVoice = [[AVSpeechSynthesisVoice.speechVoices filteredArrayUsingPredicate:predicate] firstObject];
}
if (!text && file.length > 0) {
NSError *error = nil;
text = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:&error];
if (!text) {
printf("%s\n", error.localizedDescription.UTF8String);
return 1;
}
}
if (!text) {
const int bufsize = 1024;
char buffer[bufsize];
NSMutableData* data = [[NSMutableData alloc] init];
ssize_t count = 0;
while ((count = read(fileno(thread_stdin), buffer, bufsize-1))) {
[data appendBytes:buffer length:count];
}
text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
if (!text) {
printf("%s\n", usage.UTF8String);
return 1;
}
AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString: text];
if (rate) {
utterance.rate = rate.floatValue;
}
utterance.pitchMultiplier = 1;
if (speechVoice) {
utterance.voice = speechVoice;
}
SpeechSynthesizerDelegate *delegate = [[SpeechSynthesizerDelegate alloc] init];
AVSpeechSynthesizer *synth = [[AVSpeechSynthesizer alloc] init];
synth.delegate = delegate;
[synth speakUtterance:utterance];
[delegate wait];
return 0;
}