Last set of CW Pro 5 projects (probably)
[python/dscho.git] / Mac / Modules / macspeechmodule.c
bloba6fbddd645eea207651a22a09cbc2793ed3ecc21
1 /***********************************************************
2 Copyright 1991-1997 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 ******************************************************************/
26 #include "Python.h"
27 #include "macglue.h"
29 #include <Gestalt.h>
30 #include "Speech.h"
32 #ifdef __MWERKS__
33 #define OLDP2C 1
34 #include <TextUtils.h>
35 #ifndef c2pstr
36 #define c2pstr C2PStr
37 #endif
38 #ifndef p2cstr
39 #define p2cstr P2CStr
40 #endif
41 #else
42 #include "pascal.h"
43 #endif /* __MWERKS__ */
45 #ifdef __powerc
46 #include <CodeFragments.h>
47 int lib_available;
48 #endif /* __powerc */
50 /* Somehow the Apple Fix2X and X2Fix don't do what I expect */
51 #define fixed2double(x) (((double)(x))/32768.0)
52 #define double2fixed(x) ((Fixed)((x)*32768.0))
54 char *CurrentSpeech;
55 PyObject *ms_error_object;
56 int speech_available;
58 static
59 init_available() {
60 OSErr err;
61 long result;
63 #ifdef __powerc
64 lib_available = ((ProcPtr)SpeakString != (ProcPtr)0);
65 #endif
66 err = Gestalt(gestaltSpeechAttr, &result);
67 if ( err == noErr && (result & (1<<gestaltSpeechMgrPresent)))
68 return 1;
69 return 0;
72 static
73 check_available() {
74 if ( !speech_available ) {
75 PyErr_SetString(ms_error_object, "Speech Mgr not available");
76 return 0;
78 #ifdef __powerc
79 if ( !lib_available ) {
80 PyErr_SetString(ms_error_object, "Speech Mgr available, but shared lib missing");
81 return 0;
83 #endif
84 return 1;
87 /* -------------
89 ** Part one - the speech channel object
91 typedef struct {
92 PyObject_HEAD
93 SpeechChannel chan;
94 PyObject *curtext; /* If non-NULL current text being spoken */
95 } scobject;
97 staticforward PyTypeObject sctype;
99 #define is_scobject(v) ((v)->ob_type == &sctype)
101 static scobject *
102 newscobject(arg)
103 VoiceSpec *arg;
105 scobject *self;
106 OSErr err;
108 self = PyObject_NEW(scobject, &sctype);
109 if (self == NULL)
110 return NULL;
111 if ( (err=NewSpeechChannel(arg, &self->chan)) != 0) {
112 Py_DECREF(self);
113 return (scobject *)PyErr_Mac(ms_error_object, err);
115 self->curtext = NULL;
116 return self;
119 /* sc methods */
121 static void
122 sc_dealloc(self)
123 scobject *self;
125 DisposeSpeechChannel(self->chan);
126 PyMem_DEL(self);
129 static PyObject *
130 sc_Stop(self, args)
131 scobject *self;
132 PyObject *args;
134 OSErr err;
136 if (!PyArg_NoArgs(args))
137 return NULL;
138 if ((err=StopSpeech(self->chan)) != 0) {
139 PyErr_Mac(ms_error_object, err);
140 return NULL;
142 if ( self->curtext ) {
143 Py_DECREF(self->curtext);
144 self->curtext = NULL;
146 Py_INCREF(Py_None);
147 return Py_None;
150 static PyObject *
151 sc_SpeakText(self, args)
152 scobject *self;
153 PyObject *args;
155 OSErr err;
156 char *str;
157 int len;
159 if (!PyArg_Parse(args, "s#", &str, &len))
160 return NULL;
161 if ( self->curtext ) {
162 StopSpeech(self->chan);
163 Py_DECREF(self->curtext);
164 self->curtext = NULL;
166 if ((err=SpeakText(self->chan, (Ptr)str, (long)len)) != 0) {
167 PyErr_Mac(ms_error_object, err);
168 return 0;
170 (void)PyArg_Parse(args, "O", &self->curtext); /* Or should I check this? */
171 Py_INCREF(self->curtext);
172 Py_INCREF(Py_None);
173 return Py_None;
176 static PyObject *
177 sc_GetRate(self, args)
178 scobject *self;
179 PyObject *args;
181 OSErr err;
182 Fixed farg;
184 if (!PyArg_NoArgs(args))
185 return NULL;
186 if ((err=GetSpeechRate(self->chan, &farg)) != 0) {
187 PyErr_Mac(ms_error_object, err);
188 return 0;
190 return PyFloat_FromDouble(fixed2double(farg));
193 static PyObject *
194 sc_GetPitch(self, args)
195 scobject *self;
196 PyObject *args;
198 OSErr err;
199 Fixed farg;
201 if (!PyArg_NoArgs(args))
202 return NULL;
203 if ((err=GetSpeechPitch(self->chan, &farg)) != 0) {
204 PyErr_Mac(ms_error_object, err);
205 return 0;
207 return PyFloat_FromDouble(fixed2double(farg));
210 static PyObject *
211 sc_SetRate(self, args)
212 scobject *self;
213 PyObject *args;
215 OSErr err;
216 double darg;
218 if (!PyArg_Parse(args, "d", &darg))
219 return NULL;
220 if ((err=SetSpeechRate(self->chan, double2fixed(darg))) != 0) {
221 PyErr_Mac(ms_error_object, err);
222 return 0;
224 Py_INCREF(Py_None);
225 return Py_None;
228 static PyObject *
229 sc_SetPitch(self, args)
230 scobject *self;
231 PyObject *args;
233 OSErr err;
234 double darg;
236 if (!PyArg_Parse(args, "d", &darg))
237 return NULL;
238 if ((err=SetSpeechPitch(self->chan, double2fixed(darg))) != 0) {
239 PyErr_Mac(ms_error_object, err);
240 return NULL;
242 Py_INCREF(Py_None);
243 return Py_None;
246 static struct PyMethodDef sc_methods[] = {
247 {"Stop", (PyCFunction)sc_Stop},
248 {"SetRate", (PyCFunction)sc_SetRate},
249 {"GetRate", (PyCFunction)sc_GetRate},
250 {"SetPitch", (PyCFunction)sc_SetPitch},
251 {"GetPitch", (PyCFunction)sc_GetPitch},
252 {"SpeakText", (PyCFunction)sc_SpeakText},
253 {NULL, NULL} /* sentinel */
256 static PyObject *
257 sc_getattr(self, name)
258 scobject *self;
259 char *name;
261 return Py_FindMethod(sc_methods, (PyObject *)self, name);
264 static PyTypeObject sctype = {
265 PyObject_HEAD_INIT(&PyType_Type)
266 0, /*ob_size*/
267 "MacSpeechChannel", /*tp_name*/
268 sizeof(scobject), /*tp_basicsize*/
269 0, /*tp_itemsize*/
270 /* methods */
271 (destructor)sc_dealloc, /*tp_dealloc*/
272 0, /*tp_print*/
273 (getattrfunc)sc_getattr, /*tp_getattr*/
274 0, /*tp_setattr*/
275 0, /*tp_compare*/
276 0, /*tp_repr*/
277 0, /*tp_as_number*/
278 0, /*tp_as_sequence*/
279 0, /*tp_as_mapping*/
280 0, /*tp_hash*/
283 /* -------------
285 ** Part two - the voice object
287 typedef struct {
288 PyObject_HEAD
289 int initialized;
290 VoiceSpec vs;
291 VoiceDescription vd;
292 } mvobject;
294 staticforward PyTypeObject mvtype;
296 #define is_mvobject(v) ((v)->ob_type == &mvtype)
298 static mvobject *
299 newmvobject()
301 mvobject *self;
302 self = PyObject_NEW(mvobject, &mvtype);
303 if (self == NULL)
304 return NULL;
305 self->initialized = 0;
306 return self;
309 static int
310 initmvobject(self, ind)
311 mvobject *self;
312 int ind;
314 OSErr err;
316 if ( (err=GetIndVoice((short)ind, &self->vs)) != 0 ) {
317 PyErr_Mac(ms_error_object, err);
318 return 0;
320 if ( (err=GetVoiceDescription(&self->vs, &self->vd, sizeof self->vd)) != 0) {
321 PyErr_Mac(ms_error_object, err);
322 return 0;
324 self->initialized = 1;
325 return 1;
327 /* mv methods */
329 static void
330 mv_dealloc(self)
331 mvobject *self;
333 PyMem_DEL(self);
336 static PyObject *
337 mv_getgender(self, args)
338 mvobject *self;
339 PyObject *args;
341 PyObject *rv;
343 if (!PyArg_NoArgs(args))
344 return NULL;
345 if (!self->initialized) {
346 PyErr_SetString(ms_error_object, "Uninitialized voice");
347 return NULL;
349 rv = PyInt_FromLong(self->vd.gender);
350 return rv;
353 static PyObject *
354 mv_newchannel(self, args)
355 mvobject *self;
356 PyObject *args;
358 if (!PyArg_NoArgs(args))
359 return NULL;
360 if (!self->initialized) {
361 PyErr_SetString(ms_error_object, "Uninitialized voice");
362 return NULL;
364 return (PyObject *)newscobject(&self->vs);
367 static struct PyMethodDef mv_methods[] = {
368 {"GetGender", (PyCFunction)mv_getgender},
369 {"NewChannel", (PyCFunction)mv_newchannel},
370 {NULL, NULL} /* sentinel */
373 static PyObject *
374 mv_getattr(self, name)
375 mvobject *self;
376 char *name;
378 return Py_FindMethod(mv_methods, (PyObject *)self, name);
381 static PyTypeObject mvtype = {
382 PyObject_HEAD_INIT(&PyType_Type)
383 0, /*ob_size*/
384 "MacVoice", /*tp_name*/
385 sizeof(mvobject), /*tp_basicsize*/
386 0, /*tp_itemsize*/
387 /* methods */
388 (destructor)mv_dealloc, /*tp_dealloc*/
389 0, /*tp_print*/
390 (getattrfunc)mv_getattr, /*tp_getattr*/
391 0, /*tp_setattr*/
392 0, /*tp_compare*/
393 0, /*tp_repr*/
394 0, /*tp_as_number*/
395 0, /*tp_as_sequence*/
396 0, /*tp_as_mapping*/
397 0, /*tp_hash*/
401 /* -------------
403 ** Part three - The module interface
406 /* See if Speech manager available */
408 static PyObject *
409 ms_Available(self, args)
410 PyObject *self; /* Not used */
411 PyObject *args;
414 if (!PyArg_NoArgs(args))
415 return NULL;
416 return PyInt_FromLong(speech_available);
419 /* Count number of busy speeches */
421 static PyObject *
422 ms_Busy(self, args)
423 PyObject *self; /* Not used */
424 PyObject *args;
426 short result;
428 if (!PyArg_NoArgs(args))
429 return NULL;
430 if ( !check_available() )
431 return NULL;
432 result = SpeechBusy();
433 return PyInt_FromLong(result);
436 /* Say something */
438 static PyObject *
439 ms_SpeakString(self, args)
440 PyObject *self; /* Not used */
441 PyObject *args;
443 OSErr err;
444 char *str;
445 int len;
447 if (!PyArg_Parse(args, "s", &str))
448 return NULL;
449 if ( !check_available())
450 return NULL;
451 if (CurrentSpeech) {
452 /* Free the old speech, after killing it off
453 ** (note that speach is async and c2pstr works inplace)
455 SpeakString("\p");
456 free(CurrentSpeech);
458 len = strlen(str);
459 CurrentSpeech = malloc(len+1);
460 strcpy(CurrentSpeech, str);
461 err = SpeakString(c2pstr(CurrentSpeech));
462 if ( err ) {
463 PyErr_Mac(ms_error_object, err);
464 return NULL;
466 Py_INCREF(Py_None);
467 return Py_None;
471 /* Count number of available voices */
473 static PyObject *
474 ms_CountVoices(self, args)
475 PyObject *self; /* Not used */
476 PyObject *args;
478 short result;
480 if (!PyArg_NoArgs(args))
481 return NULL;
482 if ( !check_available())
483 return NULL;
484 CountVoices(&result);
485 return PyInt_FromLong(result);
488 static PyObject *
489 ms_GetIndVoice(self, args)
490 PyObject *self; /* Not used */
491 PyObject *args;
493 mvobject *rv;
494 long ind;
496 if( !PyArg_Parse(args, "i", &ind))
497 return NULL;
498 if ( !check_available() )
499 return NULL;
500 rv = newmvobject();
501 if ( !initmvobject(rv, ind) ) {
502 Py_DECREF(rv);
503 return NULL;
505 return (PyObject *)rv;
509 static PyObject *
510 ms_Version(self, args)
511 PyObject *self; /* Not used */
512 PyObject *args;
514 NumVersion v;
516 if (!PyArg_NoArgs(args))
517 return NULL;
518 if ( !check_available())
519 return NULL;
520 v = SpeechManagerVersion();
521 return PyInt_FromLong(*(int *)&v);
525 /* List of functions defined in the module */
527 static struct PyMethodDef ms_methods[] = {
528 {"Available", ms_Available},
529 {"CountVoices", ms_CountVoices},
530 {"Busy", ms_Busy},
531 {"SpeakString", ms_SpeakString},
532 {"GetIndVoice", ms_GetIndVoice},
533 {"Version", ms_Version},
534 {NULL, NULL} /* sentinel */
537 /* Initialization function for the module (*must* be called initmacspeech) */
539 void
540 initmacspeech()
542 PyObject *m, *d;
544 speech_available = init_available();
545 /* Create the module and add the functions */
546 m = Py_InitModule("macspeech", ms_methods);
548 /* Add some symbolic constants to the module */
549 d = PyModule_GetDict(m);
550 ms_error_object = PyErr_NewException("macspeech.error", NULL, NULL);
551 PyDict_SetItemString(d, "error", ms_error_object);