blob: 6a6e3d5a5eb22878c63ce8bd64b4463877d2f9ed [file] [log] [blame]
Guido van Rossum3a80c8d1994-10-02 11:33:59 +00001/***********************************************************
Guido van Rossum99546991995-01-08 14:33:34 +00002Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
Guido van Rossum3a80c8d1994-10-02 11:33:59 +00004
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25/* xx module */
26
27#include "allobjects.h"
28#include "modsupport.h"
29
30#include <GestaltEqu.h>
Guido van Rossum3a80c8d1994-10-02 11:33:59 +000031#include "Speech.h"
32
Jack Jansen114ca5c1994-12-14 13:34:35 +000033#ifdef __MWERKS__
34#include <Strings.h>
35#define c2pstr C2PStr
36#define p2cstr P2CStr
37#else
38#include "pascal.h"
39#endif /* __MWERKS__ */
40
41#ifdef __powerc
42#include <FragLoad.h>
43int lib_available;
44#endif /* __powerc */
45
Guido van Rossum3a80c8d1994-10-02 11:33:59 +000046/* 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))
49
50char *CurrentSpeech;
51object *ms_error_object;
Jack Jansen114ca5c1994-12-14 13:34:35 +000052int speech_available;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +000053
Jack Jansen114ca5c1994-12-14 13:34:35 +000054static
55init_available() {
56 OSErr err;
57 long result;
58
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;
66}
67
68static
69check_available() {
70 if ( !speech_available ) {
71 err_setstr(ms_error_object, "Speech Mgr not available");
72 return 0;
73 }
74#ifdef __powerc
75 if ( !lib_available ) {
76 err_setstr(ms_error_object, "Speech Mgr available, but shared lib missing");
77 return 0;
78 }
79#endif
80 return 1;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +000081}
82
83/* -------------
84**
85** Part one - the speech channel object
86*/
87typedef struct {
88 OB_HEAD
Guido van Rossum3a80c8d1994-10-02 11:33:59 +000089 SpeechChannel chan;
90 object *curtext; /* If non-NULL current text being spoken */
91} scobject;
92
93staticforward typeobject sctype;
94
95#define is_scobject(v) ((v)->ob_type == &sctype)
96
97static scobject *
98newscobject(arg)
99 VoiceSpec *arg;
100{
Jack Jansen114ca5c1994-12-14 13:34:35 +0000101 scobject *self;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000102 OSErr err;
103
Jack Jansen114ca5c1994-12-14 13:34:35 +0000104 self = NEWOBJ(scobject, &sctype);
105 if (self == NULL)
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000106 return NULL;
Jack Jansen114ca5c1994-12-14 13:34:35 +0000107 if ( (err=NewSpeechChannel(arg, &self->chan)) != 0) {
108 DECREF(self);
109 return (scobject *)PyErr_Mac(ms_error_object, err);
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000110 }
Jack Jansen114ca5c1994-12-14 13:34:35 +0000111 self->curtext = NULL;
112 return self;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000113}
114
115/* sc methods */
116
117static void
Jack Jansen114ca5c1994-12-14 13:34:35 +0000118sc_dealloc(self)
119 scobject *self;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000120{
Jack Jansen114ca5c1994-12-14 13:34:35 +0000121 DisposeSpeechChannel(self->chan);
122 DEL(self);
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000123}
124
125static object *
126sc_Stop(self, args)
127 scobject *self;
128 object *args;
129{
130 OSErr err;
131
132 if (!getnoarg(args))
133 return NULL;
Jack Jansen114ca5c1994-12-14 13:34:35 +0000134 if ((err=StopSpeech(self->chan)) != 0) {
135 PyErr_Mac(ms_error_object, err);
136 return NULL;
137 }
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000138 if ( self->curtext ) {
139 DECREF(self->curtext);
140 self->curtext = NULL;
141 }
142 INCREF(None);
143 return None;
144}
145
146static object *
147sc_SpeakText(self, args)
148 scobject *self;
149 object *args;
150{
151 OSErr err;
152 char *str;
153 int len;
154
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;
161 }
Jack Jansen114ca5c1994-12-14 13:34:35 +0000162 if ((err=SpeakText(self->chan, (Ptr)str, (long)len)) != 0) {
163 PyErr_Mac(ms_error_object, err);
164 return 0;
165 }
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000166 (void)getargs(args, "O", &self->curtext); /* Or should I check this? */
167 INCREF(self->curtext);
168 INCREF(None);
169 return None;
170}
171
172static object *
173sc_GetRate(self, args)
174 scobject *self;
175 object *args;
176{
177 OSErr err;
178 Fixed farg;
179
180 if (!getnoarg(args))
181 return NULL;
Jack Jansen114ca5c1994-12-14 13:34:35 +0000182 if ((err=GetSpeechRate(self->chan, &farg)) != 0) {
183 PyErr_Mac(ms_error_object, err);
184 return 0;
185 }
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000186 return newfloatobject(fixed2double(farg));
187}
188
189static object *
190sc_GetPitch(self, args)
191 scobject *self;
192 object *args;
193{
194 OSErr err;
195 Fixed farg;
196
197 if (!getnoarg(args))
198 return NULL;
Jack Jansen114ca5c1994-12-14 13:34:35 +0000199 if ((err=GetSpeechPitch(self->chan, &farg)) != 0) {
200 PyErr_Mac(ms_error_object, err);
201 return 0;
202 }
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000203 return newfloatobject(fixed2double(farg));
204}
205
206static object *
207sc_SetRate(self, args)
208 scobject *self;
209 object *args;
210{
211 OSErr err;
212 double darg;
213
214 if (!getargs(args, "d", &darg))
215 return NULL;
Jack Jansen114ca5c1994-12-14 13:34:35 +0000216 if ((err=SetSpeechRate(self->chan, double2fixed(darg))) != 0) {
217 PyErr_Mac(ms_error_object, err);
218 return 0;
219 }
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000220 INCREF(None);
221 return None;
222}
223
224static object *
225sc_SetPitch(self, args)
226 scobject *self;
227 object *args;
228{
229 OSErr err;
230 double darg;
231
232 if (!getargs(args, "d", &darg))
233 return NULL;
Jack Jansen114ca5c1994-12-14 13:34:35 +0000234 if ((err=SetSpeechPitch(self->chan, double2fixed(darg))) != 0) {
235 PyErr_Mac(ms_error_object, err);
236 return NULL;
237 }
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000238 INCREF(None);
239 return None;
240}
241
242static 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 */
250};
251
252static object *
Jack Jansen114ca5c1994-12-14 13:34:35 +0000253sc_getattr(self, name)
254 scobject *self;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000255 char *name;
256{
Jack Jansen114ca5c1994-12-14 13:34:35 +0000257 return findmethod(sc_methods, (object *)self, name);
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000258}
259
260static 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*/
Jack Jansen114ca5c1994-12-14 13:34:35 +0000270 0, /*tp_setattr*/
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000271 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*/
277};
278
279/* -------------
280**
281** Part two - the voice object
282*/
283typedef struct {
284 OB_HEAD
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000285 int initialized;
286 VoiceSpec vs;
287 VoiceDescription vd;
288} mvobject;
289
290staticforward typeobject mvtype;
291
292#define is_mvobject(v) ((v)->ob_type == &mvtype)
293
294static mvobject *
295newmvobject()
296{
Jack Jansen114ca5c1994-12-14 13:34:35 +0000297 mvobject *self;
298 self = NEWOBJ(mvobject, &mvtype);
299 if (self == NULL)
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000300 return NULL;
Jack Jansen114ca5c1994-12-14 13:34:35 +0000301 self->initialized = 0;
302 return self;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000303}
304
305static int
306initmvobject(self, ind)
307 mvobject *self;
308 int ind;
309{
310 OSErr err;
311
312 if ( (err=GetIndVoice((short)ind, &self->vs)) != 0 ) {
Jack Jansen114ca5c1994-12-14 13:34:35 +0000313 PyErr_Mac(ms_error_object, err);
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000314 return 0;
315 }
316 if ( (err=GetVoiceDescription(&self->vs, &self->vd, sizeof self->vd)) != 0) {
Jack Jansen114ca5c1994-12-14 13:34:35 +0000317 PyErr_Mac(ms_error_object, err);
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000318 return 0;
319 }
320 self->initialized = 1;
321 return 1;
322}
323/* mv methods */
324
325static void
Jack Jansen114ca5c1994-12-14 13:34:35 +0000326mv_dealloc(self)
327 mvobject *self;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000328{
Jack Jansen114ca5c1994-12-14 13:34:35 +0000329 DEL(self);
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000330}
331
332static object *
333mv_getgender(self, args)
334 mvobject *self;
335 object *args;
336{
337 object *rv;
338
339 if (!getnoarg(args))
340 return NULL;
341 if (!self->initialized) {
342 err_setstr(ms_error_object, "Uninitialized voice");
343 return NULL;
344 }
345 rv = newintobject(self->vd.gender);
346 return rv;
347}
348
349static object *
350mv_newchannel(self, args)
351 mvobject *self;
352 object *args;
353{
354 if (!getnoarg(args))
355 return NULL;
356 if (!self->initialized) {
357 err_setstr(ms_error_object, "Uninitialized voice");
358 return NULL;
359 }
360 return (object *)newscobject(&self->vs);
361}
362
363static struct methodlist mv_methods[] = {
364 {"GetGender", (method)mv_getgender},
365 {"NewChannel", (method)mv_newchannel},
366 {NULL, NULL} /* sentinel */
367};
368
369static object *
Jack Jansen114ca5c1994-12-14 13:34:35 +0000370mv_getattr(self, name)
371 mvobject *self;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000372 char *name;
373{
Jack Jansen114ca5c1994-12-14 13:34:35 +0000374 return findmethod(mv_methods, (object *)self, name);
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000375}
376
377static 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*/
Jack Jansen114ca5c1994-12-14 13:34:35 +0000387 0, /*tp_setattr*/
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000388 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*/
394};
395
396
397/* -------------
398**
399** Part three - The module interface
400*/
401
402/* See if Speech manager available */
403
404static object *
405ms_Available(self, args)
406 object *self; /* Not used */
407 object *args;
408{
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000409
410 if (!getnoarg(args))
411 return NULL;
Jack Jansen114ca5c1994-12-14 13:34:35 +0000412 return newintobject(speech_available);
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000413}
414
415/* Count number of busy speeches */
416
417static object *
418ms_Busy(self, args)
419 object *self; /* Not used */
420 object *args;
421{
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000422 short result;
423
424 if (!getnoarg(args))
425 return NULL;
Jack Jansen114ca5c1994-12-14 13:34:35 +0000426 if ( !check_available() )
427 return NULL;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000428 result = SpeechBusy();
429 return newintobject(result);
430}
431
432/* Say something */
433
434static object *
435ms_SpeakString(self, args)
436 object *self; /* Not used */
437 object *args;
438{
439 OSErr err;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000440 char *str;
441 int len;
442
443 if (!getstrarg(args, &str))
444 return NULL;
Jack Jansen114ca5c1994-12-14 13:34:35 +0000445 if ( !check_available())
446 return NULL;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000447 if (CurrentSpeech) {
448 /* Free the old speech, after killing it off
449 ** (note that speach is async and c2pstr works inplace)
450 */
451 SpeakString("\p");
452 free(CurrentSpeech);
453 }
454 len = strlen(str);
455 CurrentSpeech = malloc(len+1);
456 strcpy(CurrentSpeech, str);
457 err = SpeakString(c2pstr(CurrentSpeech));
Jack Jansen114ca5c1994-12-14 13:34:35 +0000458 if ( err ) {
459 PyErr_Mac(ms_error_object, err);
460 return NULL;
461 }
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000462 INCREF(None);
463 return None;
464}
465
466
467/* Count number of available voices */
468
469static object *
470ms_CountVoices(self, args)
471 object *self; /* Not used */
472 object *args;
473{
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000474 short result;
475
476 if (!getnoarg(args))
477 return NULL;
Jack Jansen114ca5c1994-12-14 13:34:35 +0000478 if ( !check_available())
479 return NULL;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000480 CountVoices(&result);
481 return newintobject(result);
482}
483
484static object *
485ms_GetIndVoice(self, args)
486 object *self; /* Not used */
487 object *args;
488{
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000489 mvobject *rv;
490 long ind;
491
492 if( !getargs(args, "i", &ind))
Jack Jansen114ca5c1994-12-14 13:34:35 +0000493 return NULL;
494 if ( !check_available() )
495 return NULL;
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000496 rv = newmvobject();
497 if ( !initmvobject(rv, ind) ) {
498 DECREF(rv);
499 return NULL;
500 }
501 return (object *)rv;
502}
503
504
Jack Jansen114ca5c1994-12-14 13:34:35 +0000505static object *
506ms_Version(self, args)
507 object *self; /* Not used */
508 object *args;
509{
Jack Jansen114ca5c1994-12-14 13:34:35 +0000510 NumVersion v;
511
512 if (!getnoarg(args))
513 return NULL;
514 if ( !check_available())
515 return NULL;
516 v = SpeechManagerVersion();
517 return newintobject(*(int *)&v);
518}
519
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000520
521/* List of functions defined in the module */
522
523static struct methodlist ms_methods[] = {
524 {"Available", ms_Available},
525 {"CountVoices", ms_CountVoices},
526 {"Busy", ms_Busy},
527 {"SpeakString", ms_SpeakString},
528 {"GetIndVoice", ms_GetIndVoice},
Jack Jansen114ca5c1994-12-14 13:34:35 +0000529 {"Version", ms_Version},
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000530 {NULL, NULL} /* sentinel */
531};
532
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000533/* Initialization function for the module (*must* be called initmacspeech) */
534
535void
536initmacspeech()
537{
538 object *m, *d;
539
Jack Jansen114ca5c1994-12-14 13:34:35 +0000540 speech_available = init_available();
Guido van Rossum3a80c8d1994-10-02 11:33:59 +0000541 /* Create the module and add the functions */
542 m = initmodule("macspeech", ms_methods);
543
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);
548
549 /* Check for errors */
550 if (err_occurred())
551 fatal("can't initialize module macspeech");
552}