Another batch of updates...
[python/dscho.git] / Mac / Modules / macspeechmodule.c
blob6a6e3d5a5eb22878c63ce8bd64b4463877d2f9ed
1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3 The Netherlands.
5 All Rights Reserved
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* xx module */
27 #include "allobjects.h"
28 #include "modsupport.h"
30 #include <GestaltEqu.h>
31 #include "Speech.h"
33 #ifdef __MWERKS__
34 #include <Strings.h>
35 #define c2pstr C2PStr
36 #define p2cstr P2CStr
37 #else
38 #include "pascal.h"
39 #endif /* __MWERKS__ */
41 #ifdef __powerc
42 #include <FragLoad.h>
43 int lib_available;
44 #endif /* __powerc */
46 /* Somehow the Apple Fix2X and X2Fix don't do what I expect */
47 #define fixed2double(x) (((double)(x))/32768.0)
48 #define double2fixed(x) ((Fixed)((x)*32768.0))
50 char *CurrentSpeech;
51 object *ms_error_object;
52 int speech_available;
54 static
55 init_available() {
56 OSErr err;
57 long result;
59 #ifdef __powerc
60 lib_available = ((ProcPtr)SpeakString != (ProcPtr)0);
61 #endif
62 err = Gestalt(gestaltSpeechAttr, &result);
63 if ( err == noErr && (result & (1<<gestaltSpeechMgrPresent)))
64 return 1;
65 return 0;
68 static
69 check_available() {
70 if ( !speech_available ) {
71 err_setstr(ms_error_object, "Speech Mgr not available");
72 return 0;
74 #ifdef __powerc
75 if ( !lib_available ) {
76 err_setstr(ms_error_object, "Speech Mgr available, but shared lib missing");
77 return 0;
79 #endif
80 return 1;
83 /* -------------
85 ** Part one - the speech channel object
87 typedef struct {
88 OB_HEAD
89 SpeechChannel chan;
90 object *curtext; /* If non-NULL current text being spoken */
91 } scobject;
93 staticforward typeobject sctype;
95 #define is_scobject(v) ((v)->ob_type == &sctype)
97 static scobject *
98 newscobject(arg)
99 VoiceSpec *arg;
101 scobject *self;
102 OSErr err;
104 self = NEWOBJ(scobject, &sctype);
105 if (self == NULL)
106 return NULL;
107 if ( (err=NewSpeechChannel(arg, &self->chan)) != 0) {
108 DECREF(self);
109 return (scobject *)PyErr_Mac(ms_error_object, err);
111 self->curtext = NULL;
112 return self;
115 /* sc methods */
117 static void
118 sc_dealloc(self)
119 scobject *self;
121 DisposeSpeechChannel(self->chan);
122 DEL(self);
125 static object *
126 sc_Stop(self, args)
127 scobject *self;
128 object *args;
130 OSErr err;
132 if (!getnoarg(args))
133 return NULL;
134 if ((err=StopSpeech(self->chan)) != 0) {
135 PyErr_Mac(ms_error_object, err);
136 return NULL;
138 if ( self->curtext ) {
139 DECREF(self->curtext);
140 self->curtext = NULL;
142 INCREF(None);
143 return None;
146 static object *
147 sc_SpeakText(self, args)
148 scobject *self;
149 object *args;
151 OSErr err;
152 char *str;
153 int len;
155 if (!getargs(args, "s#", &str, &len))
156 return NULL;
157 if ( self->curtext ) {
158 StopSpeech(self->chan);
159 DECREF(self->curtext);
160 self->curtext = NULL;
162 if ((err=SpeakText(self->chan, (Ptr)str, (long)len)) != 0) {
163 PyErr_Mac(ms_error_object, err);
164 return 0;
166 (void)getargs(args, "O", &self->curtext); /* Or should I check this? */
167 INCREF(self->curtext);
168 INCREF(None);
169 return None;
172 static object *
173 sc_GetRate(self, args)
174 scobject *self;
175 object *args;
177 OSErr err;
178 Fixed farg;
180 if (!getnoarg(args))
181 return NULL;
182 if ((err=GetSpeechRate(self->chan, &farg)) != 0) {
183 PyErr_Mac(ms_error_object, err);
184 return 0;
186 return newfloatobject(fixed2double(farg));
189 static object *
190 sc_GetPitch(self, args)
191 scobject *self;
192 object *args;
194 OSErr err;
195 Fixed farg;
197 if (!getnoarg(args))
198 return NULL;
199 if ((err=GetSpeechPitch(self->chan, &farg)) != 0) {
200 PyErr_Mac(ms_error_object, err);
201 return 0;
203 return newfloatobject(fixed2double(farg));
206 static object *
207 sc_SetRate(self, args)
208 scobject *self;
209 object *args;
211 OSErr err;
212 double darg;
214 if (!getargs(args, "d", &darg))
215 return NULL;
216 if ((err=SetSpeechRate(self->chan, double2fixed(darg))) != 0) {
217 PyErr_Mac(ms_error_object, err);
218 return 0;
220 INCREF(None);
221 return None;
224 static object *
225 sc_SetPitch(self, args)
226 scobject *self;
227 object *args;
229 OSErr err;
230 double darg;
232 if (!getargs(args, "d", &darg))
233 return NULL;
234 if ((err=SetSpeechPitch(self->chan, double2fixed(darg))) != 0) {
235 PyErr_Mac(ms_error_object, err);
236 return NULL;
238 INCREF(None);
239 return None;
242 static struct methodlist sc_methods[] = {
243 {"Stop", (method)sc_Stop},
244 {"SetRate", (method)sc_SetRate},
245 {"GetRate", (method)sc_GetRate},
246 {"SetPitch", (method)sc_SetPitch},
247 {"GetPitch", (method)sc_GetPitch},
248 {"SpeakText", (method)sc_SpeakText},
249 {NULL, NULL} /* sentinel */
252 static object *
253 sc_getattr(self, name)
254 scobject *self;
255 char *name;
257 return findmethod(sc_methods, (object *)self, name);
260 static typeobject sctype = {
261 OB_HEAD_INIT(&Typetype)
262 0, /*ob_size*/
263 "MacSpeechChannel", /*tp_name*/
264 sizeof(scobject), /*tp_basicsize*/
265 0, /*tp_itemsize*/
266 /* methods */
267 (destructor)sc_dealloc, /*tp_dealloc*/
268 0, /*tp_print*/
269 (getattrfunc)sc_getattr, /*tp_getattr*/
270 0, /*tp_setattr*/
271 0, /*tp_compare*/
272 0, /*tp_repr*/
273 0, /*tp_as_number*/
274 0, /*tp_as_sequence*/
275 0, /*tp_as_mapping*/
276 0, /*tp_hash*/
279 /* -------------
281 ** Part two - the voice object
283 typedef struct {
284 OB_HEAD
285 int initialized;
286 VoiceSpec vs;
287 VoiceDescription vd;
288 } mvobject;
290 staticforward typeobject mvtype;
292 #define is_mvobject(v) ((v)->ob_type == &mvtype)
294 static mvobject *
295 newmvobject()
297 mvobject *self;
298 self = NEWOBJ(mvobject, &mvtype);
299 if (self == NULL)
300 return NULL;
301 self->initialized = 0;
302 return self;
305 static int
306 initmvobject(self, ind)
307 mvobject *self;
308 int ind;
310 OSErr err;
312 if ( (err=GetIndVoice((short)ind, &self->vs)) != 0 ) {
313 PyErr_Mac(ms_error_object, err);
314 return 0;
316 if ( (err=GetVoiceDescription(&self->vs, &self->vd, sizeof self->vd)) != 0) {
317 PyErr_Mac(ms_error_object, err);
318 return 0;
320 self->initialized = 1;
321 return 1;
323 /* mv methods */
325 static void
326 mv_dealloc(self)
327 mvobject *self;
329 DEL(self);
332 static object *
333 mv_getgender(self, args)
334 mvobject *self;
335 object *args;
337 object *rv;
339 if (!getnoarg(args))
340 return NULL;
341 if (!self->initialized) {
342 err_setstr(ms_error_object, "Uninitialized voice");
343 return NULL;
345 rv = newintobject(self->vd.gender);
346 return rv;
349 static object *
350 mv_newchannel(self, args)
351 mvobject *self;
352 object *args;
354 if (!getnoarg(args))
355 return NULL;
356 if (!self->initialized) {
357 err_setstr(ms_error_object, "Uninitialized voice");
358 return NULL;
360 return (object *)newscobject(&self->vs);
363 static struct methodlist mv_methods[] = {
364 {"GetGender", (method)mv_getgender},
365 {"NewChannel", (method)mv_newchannel},
366 {NULL, NULL} /* sentinel */
369 static object *
370 mv_getattr(self, name)
371 mvobject *self;
372 char *name;
374 return findmethod(mv_methods, (object *)self, name);
377 static typeobject mvtype = {
378 OB_HEAD_INIT(&Typetype)
379 0, /*ob_size*/
380 "MacVoice", /*tp_name*/
381 sizeof(mvobject), /*tp_basicsize*/
382 0, /*tp_itemsize*/
383 /* methods */
384 (destructor)mv_dealloc, /*tp_dealloc*/
385 0, /*tp_print*/
386 (getattrfunc)mv_getattr, /*tp_getattr*/
387 0, /*tp_setattr*/
388 0, /*tp_compare*/
389 0, /*tp_repr*/
390 0, /*tp_as_number*/
391 0, /*tp_as_sequence*/
392 0, /*tp_as_mapping*/
393 0, /*tp_hash*/
397 /* -------------
399 ** Part three - The module interface
402 /* See if Speech manager available */
404 static object *
405 ms_Available(self, args)
406 object *self; /* Not used */
407 object *args;
410 if (!getnoarg(args))
411 return NULL;
412 return newintobject(speech_available);
415 /* Count number of busy speeches */
417 static object *
418 ms_Busy(self, args)
419 object *self; /* Not used */
420 object *args;
422 short result;
424 if (!getnoarg(args))
425 return NULL;
426 if ( !check_available() )
427 return NULL;
428 result = SpeechBusy();
429 return newintobject(result);
432 /* Say something */
434 static object *
435 ms_SpeakString(self, args)
436 object *self; /* Not used */
437 object *args;
439 OSErr err;
440 char *str;
441 int len;
443 if (!getstrarg(args, &str))
444 return NULL;
445 if ( !check_available())
446 return NULL;
447 if (CurrentSpeech) {
448 /* Free the old speech, after killing it off
449 ** (note that speach is async and c2pstr works inplace)
451 SpeakString("\p");
452 free(CurrentSpeech);
454 len = strlen(str);
455 CurrentSpeech = malloc(len+1);
456 strcpy(CurrentSpeech, str);
457 err = SpeakString(c2pstr(CurrentSpeech));
458 if ( err ) {
459 PyErr_Mac(ms_error_object, err);
460 return NULL;
462 INCREF(None);
463 return None;
467 /* Count number of available voices */
469 static object *
470 ms_CountVoices(self, args)
471 object *self; /* Not used */
472 object *args;
474 short result;
476 if (!getnoarg(args))
477 return NULL;
478 if ( !check_available())
479 return NULL;
480 CountVoices(&result);
481 return newintobject(result);
484 static object *
485 ms_GetIndVoice(self, args)
486 object *self; /* Not used */
487 object *args;
489 mvobject *rv;
490 long ind;
492 if( !getargs(args, "i", &ind))
493 return NULL;
494 if ( !check_available() )
495 return NULL;
496 rv = newmvobject();
497 if ( !initmvobject(rv, ind) ) {
498 DECREF(rv);
499 return NULL;
501 return (object *)rv;
505 static object *
506 ms_Version(self, args)
507 object *self; /* Not used */
508 object *args;
510 NumVersion v;
512 if (!getnoarg(args))
513 return NULL;
514 if ( !check_available())
515 return NULL;
516 v = SpeechManagerVersion();
517 return newintobject(*(int *)&v);
521 /* List of functions defined in the module */
523 static struct methodlist ms_methods[] = {
524 {"Available", ms_Available},
525 {"CountVoices", ms_CountVoices},
526 {"Busy", ms_Busy},
527 {"SpeakString", ms_SpeakString},
528 {"GetIndVoice", ms_GetIndVoice},
529 {"Version", ms_Version},
530 {NULL, NULL} /* sentinel */
533 /* Initialization function for the module (*must* be called initmacspeech) */
535 void
536 initmacspeech()
538 object *m, *d;
540 speech_available = init_available();
541 /* Create the module and add the functions */
542 m = initmodule("macspeech", ms_methods);
544 /* Add some symbolic constants to the module */
545 d = getmoduledict(m);
546 ms_error_object = newstringobject("macspeech.error");
547 dictinsert(d, "error", ms_error_object);
549 /* Check for errors */
550 if (err_occurred())
551 fatal("can't initialize module macspeech");