Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 294 lines (238 sloc) 9.006 kb
dc5be1c Initial check-in.
uli authored
1 //
2 // UKSpeechSettingsView.m
3 // CocoaMoose
4 //
5 // Created by Uli Kusterer on Mon Apr 05 2004.
720b0e7 @uliwitness Added licensing information to the source files.
authored
6 // Copyright (c) 2004 M. Uli Kusterer. Uli Kusterer
7 //
8 // This software is provided 'as-is', without any express or implied
9 // warranty. In no event will the authors be held liable for any damages
10 // arising from the use of this software.
11 //
12 // Permission is granted to anyone to use this software for any purpose,
13 // including commercial applications, and to alter it and redistribute it
14 // freely, subject to the following restrictions:
15 //
16 // 1. The origin of this software must not be misrepresented; you must not
17 // claim that you wrote the original software. If you use this software
18 // in a product, an acknowledgment in the product documentation would be
19 // appreciated but is not required.
20 //
21 // 2. Altered source versions must be plainly marked as such, and must not be
22 // misrepresented as being the original software.
23 //
24 // 3. This notice may not be removed or altered from any source
25 // distribution.
dc5be1c Initial check-in.
uli authored
26 //
27
28 #import "UKSpeechSettingsView.h"
88737da @uliwitness Less NIB leakage in UKSpeechSettingsView
authored
29 #import "UKHelperMacros.h"
dc5be1c Initial check-in.
uli authored
30
31
32 NSString* UKSpeechPitchBaseProperty = NULL;
33
34
88737da @uliwitness Less NIB leakage in UKSpeechSettingsView
authored
35 // These are here so we don't have to pull in UKSpeechSynthesizer on 10.5:
dc5be1c Initial check-in.
uli authored
36 @interface NSObject (UKSpeechSynthExtensions)
37
38 -(void) setVolume: (float)n;
39 -(float) volume;
40
41 -(id) objectForProperty:(NSString *)property error:(NSError **)outError;
42 -(BOOL) setObject:(id)object forProperty:(NSString *)property error:(NSError **)outError;
43
44 -(void) setRate: (float)n;
45 -(float) rate;
46
47 @end
48
49
50 @implementation UKSpeechSettingsView
51
52 +(void) load
53 {
54 if( UKSpeechPitchBaseProperty == NULL )
55 {
56 void* dataPtr = NULL;
57 CFBundleRef cocoaBundle = CFBundleGetBundleWithIdentifier( CFSTR("com.apple.Cocoa") );
58 if( !cocoaBundle )
59 cocoaBundle = CFBundleGetBundleWithIdentifier( CFSTR("com.apple.cocoa") );
60 if( cocoaBundle )
61 dataPtr = CFBundleGetDataPointerForName( cocoaBundle, CFSTR("NSSpeechPitchBaseProperty") );
62 if( !dataPtr )
63 {
64 CFBundleRef fallbackBundle = CFBundleGetBundleWithIdentifier( CFSTR("de.zathras.moose.ukspeechsynthesizer") );
65 if( fallbackBundle )
66 dataPtr = CFBundleGetDataPointerForName( fallbackBundle, CFSTR("NSSpeechPitchBaseProperty") );
67 }
68 if( dataPtr )
69 UKSpeechPitchBaseProperty = *(NSString**)dataPtr;
70 else
71 UKSpeechPitchBaseProperty = @"NSSpeechPitchBaseProperty";
72 }
73 }
74
75 -(void) awakeFromNib
76 {
77 static BOOL isAwaking = NO;
78 NSPoint pos = { 0, 0 };
79
80 if( !isAwaking )
81 {
82 isAwaking = YES;
88737da @uliwitness Less NIB leakage in UKSpeechSettingsView
authored
83
84 topLevelObjects = [[NSMutableArray alloc] init];
85 NSDictionary* ent = [NSDictionary dictionaryWithObjectsAndKeys:
86 self, @"NSOwner",
87 topLevelObjects, @"NSTopLevelObjects",
88 nil];
89 NSBundle* mainB = [NSBundle bundleForClass: [self class]];
90 [mainB loadNibFile: [self nibName] externalNameTable: ent withZone: [self zone]]; // We're responsible for releasing the top-level objects in the NIB (our view, right now).
91 if( [topLevelObjects count] == 0 )
92 {
93 NSLog( @"%@: Couldn't find NIB file \"%@.nib\".", NSStringFromClass([self class]), [self nibName] );
94 return;
95 }
96
dc5be1c Initial check-in.
uli authored
97 pos.y += [self frame].size.height -[mainView frame].size.height;
98 [mainView setFrameOrigin: pos];
99 [self addSubview: mainView];
100 [mainView setAutoresizingMask: NSViewWidthSizable | NSViewMinXMargin | NSViewMaxXMargin | NSViewMinYMargin];
101
102 [voicePopup removeAllItems];
103 NSEnumerator* enny = [[NSSpeechSynthesizer availableVoices] objectEnumerator];
104 NSString* voiceID = nil;
105 while( (voiceID = [enny nextObject]) )
106 {
107 [voicePopup addItemWithTitle: [[NSSpeechSynthesizer attributesForVoice: voiceID] objectForKey: NSVoiceName]];
108 }
109 if( speechSynthesizer )
110 [self reflectVoiceInUI: nil];
111 isAwaking = NO;
112 }
113 }
114
88737da @uliwitness Less NIB leakage in UKSpeechSettingsView
authored
115
116 -(NSString*) nibName
117 {
118 return NSStringFromClass([self class]);
119 }
120
121
dc5be1c Initial check-in.
uli authored
122 -(void) dealloc
123 {
88737da @uliwitness Less NIB leakage in UKSpeechSettingsView
authored
124 DESTROY_DEALLOC( mainView );
125 DESTROY_DEALLOC( speechSynthesizer );
126 DESTROY_DEALLOC( topLevelObjects );
dc5be1c Initial check-in.
uli authored
127
128 [super dealloc];
129 }
130
131
132 -(IBAction) voiceChanged: (id)sender
133 {
134 NSString* currVoice = [[NSSpeechSynthesizer availableVoices] objectAtIndex: [voicePopup indexOfSelectedItem]];
135 [speechSynthesizer setVoice: currVoice];
136 [self reflectVoiceInUI: nil];
137 }
138
139 -(IBAction) pitchChanged: (id)sender
140 {
141 [speechSynthesizer setObject: [NSNumber numberWithFloat: [pitchStepper floatValue]] forProperty: UKSpeechPitchBaseProperty error: nil];
142 [pitchField setDoubleValue: [pitchStepper floatValue]];
143 }
144
145
146 -(IBAction) volumeChanged: (id)sender
147 {
148 [speechSynthesizer setVolume: [volumeSlider floatValue]];
149 }
150
151
152 -(IBAction) rateChanged: (id)sender
153 {
154 [speechSynthesizer setRate: [rateStepper floatValue]];
155 [rateField setFloatValue: [rateStepper floatValue]];
156 }
157
158
159 -(void) reflectVoiceInUI: (id)sender
160 {
161 NSDictionary* attrs = [NSSpeechSynthesizer attributesForVoice: [speechSynthesizer voice]];
162 if( attrs == nil )
163 attrs = [NSSpeechSynthesizer attributesForVoice: @"com.apple.speech.synthesis.voice.Fred"];
164 NSString* demoTextStr = [attrs objectForKey: NSVoiceDemoText];
165 if( !demoTextStr )
166 demoTextStr = @"Some nit didn't provide a demo text for this voice.";
167 [demoText setString: demoTextStr];
168 NSString* currName = [attrs objectForKey: NSVoiceName];
169 if( currName )
170 [voicePopup selectItemWithTitle: currName];
171 NSString* gender = [attrs objectForKey: NSVoiceGender];
172 if( [gender isEqualToString: NSVoiceGenderNeuter] )
173 gender = @"Neuter";
174 else if( [gender isEqualToString: NSVoiceGenderMale] )
175 gender = @"Male";
176 else if( [gender isEqualToString: NSVoiceGenderFemale] )
177 gender = @"Female";
178 [genderField setStringValue: NSLocalizedString( gender, @"" ) ];
179 [ageField setObjectValue: [attrs objectForKey: NSVoiceAge]];
180
181 if( [speechSynthesizer respondsToSelector: @selector(volume)] )
182 {
183 [pitchField setFloatValue: [[speechSynthesizer objectForProperty: UKSpeechPitchBaseProperty error: nil] floatValue]];
184 [pitchStepper setFloatValue: [pitchField floatValue]];
185 [volumeSlider setFloatValue: [speechSynthesizer volume]];
186 [rateField setFloatValue: [speechSynthesizer rate]];
187 [rateStepper setFloatValue: [rateField floatValue]];
188 }
189 else
190 {
191 [pitchField removeFromSuperview];
192 pitchField = nil;
193 [rateField removeFromSuperview];
194 rateField = nil;
195 [pitchStepper removeFromSuperview];
196 pitchStepper = nil;
197 [volumeSlider setEnabled: NO];
198 [rateStepper removeFromSuperview];
199 rateStepper = nil;
200 }
201 }
202
203
204 -(IBAction) testSpeak: (id)sender
205 {
206 [speechSynthesizer startSpeakingString: [demoText string]];
207 }
208
209
210 -(NSSpeechSynthesizer *) speechSynthesizer
211 {
212 return speechSynthesizer;
213 }
214
215 -(void) setSpeechSynthesizer: (NSSpeechSynthesizer *)newSpeechSynthesizer
216 {
217 if( speechSynthesizer != newSpeechSynthesizer )
218 {
219 [speechSynthesizer release];
220 speechSynthesizer = [newSpeechSynthesizer retain];
221
222 [self reflectVoiceInUI: nil];
223 }
224 }
225
226 @end
227
228
229 @implementation NSSpeechSynthesizer (UKSpeechSettings)
230
231 -(NSDictionary*) settingsDictionary
232 {
233 NSMutableDictionary* dict = [NSMutableDictionary dictionary];
234
235 [dict setObject: [self voice] forKey: @"voice"];
236 [dict setObject: [NSNumber numberWithInt: [self usesFeedbackWindow]] forKey: @"usesFeedbackWindow"];
237 [dict setObject: [NSNumber numberWithFloat: [self volume]] forKey: @"volume"];
238 [dict setObject: [NSNumber numberWithInt: lroundf([self volume] * 10.0f)] forKey: @"speechVolume"];
239 [dict setObject: [NSNumber numberWithFloat: [[self objectForProperty: UKSpeechPitchBaseProperty error: nil] floatValue]] forKey: @"speechPitch"];
240 [dict setObject: [NSNumber numberWithFloat: [self rate]] forKey: @"speechRate"];
241
242 return dict;
243 }
244
245
246 -(void) setSettingsDictionary: (NSDictionary*)dict
247 {
248 [self setVoice: [dict objectForKey: @"voice"]];
249 [self setUsesFeedbackWindow: [[dict objectForKey: @"usesFeedbackWindow"] boolValue]];
250 id volObj = [dict objectForKey: @"volume"];
251 float vol = 1.0f;
252 if( volObj )
253 vol = [volObj floatValue];
254 else
255 {
256 volObj = [dict objectForKey: @"speechVolume"];
257 if( volObj )
258 vol = 0.1f * (float)[volObj intValue]; // This changed from speechVolume to volume and from a 0 ... 10 scale to a 0 ... 1.0 scale. So we may have to substitute this if missing.
259 }
260 [self setVolume: vol];
261 [self setObject: [dict objectForKey: @"speechPitch"] forProperty: UKSpeechPitchBaseProperty error: nil];
262 [self setRate: [[dict objectForKey: @"speechRate"] floatValue]];
263 }
264
88737da @uliwitness Less NIB leakage in UKSpeechSettingsView
authored
265
dc5be1c Initial check-in.
uli authored
266 +(NSString*) prettifyString: (NSString*)inString
267 {
268 NSMutableString* str = [inString mutableCopy];
269 NSRange commandRange = { 0, 0 },
270 cmdEndRange;
271
272 if( !str )
273 return str;
274
275 while( commandRange.location != NSNotFound || commandRange.length != 0 )
276 {
277 commandRange = [str rangeOfString: @"[["];
278
279 if( commandRange.location == NSNotFound && commandRange.length == 0 )
280 break;
281
282 cmdEndRange = [str rangeOfString: @"]]"];
283 if( cmdEndRange.location == NSNotFound && cmdEndRange.length == 0 )
284 break;
285
286 commandRange.length += ((cmdEndRange.location +cmdEndRange.length) -(commandRange.location +commandRange.length));
287 [str deleteCharactersInRange: commandRange];
288 }
289
290 return str;
291 }
292
293 @end
Something went wrong with that request. Please try again.