Added 'description' class attribute to every command class (to help the
[python/dscho.git] / Mac / Modules / macspeechmodule.c
blobd0ee465e443d65807e046de2951f5c600901aa30
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"
28 #include <Gestalt.h>
29 #include "Speech.h"
31 #ifdef __MWERKS__
32 #include <TextUtils.h>
33 #define c2pstr C2PStr
34 #define p2cstr P2CStr
35 #else
36 #include "pascal.h"
37 #endif /* __MWERKS__ */
39 #ifdef __powerc
40 #include <CodeFragments.h>
41 int lib_available;
42 #endif /* __powerc */
44 /* Somehow the Apple Fix2X and X2Fix don't do what I expect */
45 #define fixed2double(x) (((double)(x))/32768.0)
46 #define double2fixed(x) ((Fixed)((x)*32768.0))
48 char *CurrentSpeech;
49 PyObject *ms_error_object;
50 int speech_available;
52 static
53 init_available() {
54 OSErr err;
55 long result;
57 #ifdef __powerc
58 lib_available = ((ProcPtr)SpeakString != (ProcPtr)0);
59 #endif
60 err = Gestalt(gestaltSpeechAttr, &result);
61 if ( err == noErr && (result & (1<<gestaltSpeechMgrPresent)))
62 return 1;
63 return 0;
66 static
67 check_available() {
68 if ( !speech_available ) {
69 PyErr_SetString(ms_error_object, "Speech Mgr not available");
70 return 0;
72 #ifdef __powerc
73 if ( !lib_available ) {
74 PyErr_SetString(ms_error_object, "Speech Mgr available, but shared lib missing");
75 return 0;
77 #endif
78 return 1;
81 /* -------------
83 ** Part one - the speech channel object
85 typedef struct {
86 PyObject_HEAD
87 SpeechChannel chan;
88 PyObject *curtext; /* If non-NULL current text being spoken */
89 } scobject;
91 staticforward PyTypeObject sctype;
93 #define is_scobject(v) ((v)->ob_type == &sctype)
95 static scobject *
96 newscobject(arg)
97 VoiceSpec *arg;
99 scobject *self;
100 OSErr err;
102 self = PyObject_NEW(scobject, &sctype);
103 if (self == NULL)
104 return NULL;
105 if ( (err=NewSpeechChannel(arg, &self->chan)) != 0) {
106 Py_DECREF(self);
107 return (scobject *)PyErr_Mac(ms_error_object, err);
109 self->curtext = NULL;
110 return self;
113 /* sc methods */
115 static void
116 sc_dealloc(self)
117 scobject *self;
119 DisposeSpeechChannel(self->chan);
120 PyMem_DEL(self);
123 static PyObject *
124 sc_Stop(self, args)
125 scobject *self;
126 PyObject *args;
128 OSErr err;
130 if (!PyArg_NoArgs(args))
131 return NULL;
132 if ((err=StopSpeech(self->chan)) != 0) {
133 PyErr_Mac(ms_error_object, err);
134 return NULL;
136 if ( self->curtext ) {
137 Py_DECREF(self->curtext);
138 self->curtext = NULL;
140 Py_INCREF(Py_None);
141 return Py_None;
144 static PyObject *
145 sc_SpeakText(self, args)
146 scobject *self;
147 PyObject *args;
149 OSErr err;
150 char *str;
151 int len;
153 if (!PyArg_Parse(args, "s#", &str, &len))
154 return NULL;
155 if ( self->curtext ) {
156 StopSpeech(self->chan);
157 Py_DECREF(self->curtext);
158 self->curtext = NULL;
160 if ((err=SpeakText(self->chan, (Ptr)str, (long)len)) != 0) {
161 PyErr_Mac(ms_error_object, err);
162 return 0;
164 (void)PyArg_Parse(args, "O", &self->curtext); /* Or should I check this? */
165 Py_INCREF(self->curtext);
166 Py_INCREF(Py_None);
167 return Py_None;
170 static PyObject *
171 sc_GetRate(self, args)
172 scobject *self;
173 PyObject *args;
175 OSErr err;
176 Fixed farg;
178 if (!PyArg_NoArgs(args))
179 return NULL;
180 if ((err=GetSpeechRate(self->chan, &farg)) != 0) {
181 PyErr_Mac(ms_error_object, err);
182 return 0;
184 return PyFloat_FromDouble(fixed2double(farg));
187 static PyObject *
188 sc_GetPitch(self, args)
189 scobject *self;
190 PyObject *args;
192 OSErr err;
193 Fixed farg;
195 if (!PyArg_NoArgs(args))
196 return NULL;
197 if ((err=GetSpeechPitch(self->chan, &farg)) != 0) {
198 PyErr_Mac(ms_error_object, err);
199 return 0;
201 return PyFloat_FromDouble(fixed2double(farg));
204 static PyObject *
205 sc_SetRate(self, args)
206 scobject *self;
207 PyObject *args;
209 OSErr err;
210 double darg;
212 if (!PyArg_Parse(args, "d", &darg))
213 return NULL;
214 if ((err=SetSpeechRate(self->chan, double2fixed(darg))) != 0) {
215 PyErr_Mac(ms_error_object, err);
216 return 0;
218 Py_INCREF(Py_None);
219 return Py_None;
222 static PyObject *
223 sc_SetPitch(self, args)
224 scobject *self;
225 PyObject *args;
227 OSErr err;
228 double darg;
230 if (!PyArg_Parse(args, "d", &darg))
231 return NULL;
232 if ((err=SetSpeechPitch(self->chan, double2fixed(darg))) != 0) {
233 PyErr_Mac(ms_error_object, err);
234 return NULL;
236 Py_INCREF(Py_None);
237 return Py_None;
240 static struct PyMethodDef sc_methods[] = {
241 {"Stop", (PyCFunction)sc_Stop},
242 {"SetRate", (PyCFunction)sc_SetRate},
243 {"GetRate", (PyCFunction)sc_GetRate},
244 {"SetPitch", (PyCFunction)sc_SetPitch},
245 {"GetPitch", (PyCFunction)sc_GetPitch},
246 {"SpeakText", (PyCFunction)sc_SpeakText},
247 {NULL, NULL} /* sentinel */
250 static PyObject *
251 sc_getattr(self, name)
252 scobject *self;
253 char *name;
255 return Py_FindMethod(sc_methods, (PyObject *)self, name);
258 static PyTypeObject sctype = {
259 PyObject_HEAD_INIT(&PyType_Type)
260 0, /*ob_size*/
261 "MacSpeechChannel", /*tp_name*/
262 sizeof(scobject), /*tp_basicsize*/
263 0, /*tp_itemsize*/
264 /* methods */
265 (destructor)sc_dealloc, /*tp_dealloc*/
266 0, /*tp_print*/
267 (getattrfunc)sc_getattr, /*tp_getattr*/
268 0, /*tp_setattr*/
269 0, /*tp_compare*/
270 0, /*tp_repr*/
271 0, /*tp_as_number*/
272 0, /*tp_as_sequence*/
273 0, /*tp_as_mapping*/
274 0, /*tp_hash*/
277 /* -------------
279 ** Part two - the voice object
281 typedef struct {
282 PyObject_HEAD
283 int initialized;
284 VoiceSpec vs;
285 VoiceDescription vd;
286 } mvobject;
288 staticforward PyTypeObject mvtype;
290 #define is_mvobject(v) ((v)->ob_type == &mvtype)
292 static mvobject *
293 newmvobject()
295 mvobject *self;
296 self = PyObject_NEW(mvobject, &mvtype);
297 if (self == NULL)
298 return NULL;
299 self->initialized = 0;
300 return self;
303 static int
304 initmvobject(self, ind)
305 mvobject *self;
306 int ind;
308 OSErr err;
310 if ( (err=GetIndVoice((short)ind, &self->vs)) != 0 ) {
311 PyErr_Mac(ms_error_object, err);
312 return 0;
314 if ( (err=GetVoiceDescription(&self->vs, &self->vd, sizeof self->vd)) != 0) {
315 PyErr_Mac(ms_error_object, err);
316 return 0;
318 self->initialized = 1;
319 return 1;
321 /* mv methods */
323 static void
324 mv_dealloc(self)
325 mvobject *self;
327 PyMem_DEL(self);
330 static PyObject *
331 mv_getgender(self, args)
332 mvobject *self;
333 PyObject *args;
335 PyObject *rv;
337 if (!PyArg_NoArgs(args))
338 return NULL;
339 if (!self->initialized) {
340 PyErr_SetString(ms_error_object, "Uninitialized voice");
341 return NULL;
343 rv = PyInt_FromLong(self->vd.gender);
344 return rv;
347 static PyObject *
348 mv_newchannel(self, args)
349 mvobject *self;
350 PyObject *args;
352 if (!PyArg_NoArgs(args))
353 return NULL;
354 if (!self->initialized) {
355 PyErr_SetString(ms_error_object, "Uninitialized voice");
356 return NULL;
358 return (PyObject *)newscobject(&self->vs);
361 static struct PyMethodDef mv_methods[] = {
362 {"GetGender", (PyCFunction)mv_getgender},
363 {"NewChannel", (PyCFunction)mv_newchannel},
364 {NULL, NULL} /* sentinel */
367 static PyObject *
368 mv_getattr(self, name)
369 mvobject *self;
370 char *name;
372 return Py_FindMethod(mv_methods, (PyObject *)self, name);
375 static PyTypeObject mvtype = {
376 PyObject_HEAD_INIT(&PyType_Type)
377 0, /*ob_size*/
378 "MacVoice", /*tp_name*/
379 sizeof(mvobject), /*tp_basicsize*/
380 0, /*tp_itemsize*/
381 /* methods */
382 (destructor)mv_dealloc, /*tp_dealloc*/
383 0, /*tp_print*/
384 (getattrfunc)mv_getattr, /*tp_getattr*/
385 0, /*tp_setattr*/
386 0, /*tp_compare*/
387 0, /*tp_repr*/
388 0, /*tp_as_number*/
389 0, /*tp_as_sequence*/
390 0, /*tp_as_mapping*/
391 0, /*tp_hash*/
395 /* -------------
397 ** Part three - The module interface
400 /* See if Speech manager available */
402 static PyObject *
403 ms_Available(self, args)
404 PyObject *self; /* Not used */
405 PyObject *args;
408 if (!PyArg_NoArgs(args))
409 return NULL;
410 return PyInt_FromLong(speech_available);
413 /* Count number of busy speeches */
415 static PyObject *
416 ms_Busy(self, args)
417 PyObject *self; /* Not used */
418 PyObject *args;
420 short result;
422 if (!PyArg_NoArgs(args))
423 return NULL;
424 if ( !check_available() )
425 return NULL;
426 result = SpeechBusy();
427 return PyInt_FromLong(result);
430 /* Say something */
432 static PyObject *
433 ms_SpeakString(self, args)
434 PyObject *self; /* Not used */
435 PyObject *args;
437 OSErr err;
438 char *str;
439 int len;
441 if (!PyArg_Parse(args, "s", &str))
442 return NULL;
443 if ( !check_available())
444 return NULL;
445 if (CurrentSpeech) {
446 /* Free the old speech, after killing it off
447 ** (note that speach is async and c2pstr works inplace)
449 SpeakString("\p");
450 free(CurrentSpeech);
452 len = strlen(str);
453 CurrentSpeech = malloc(len+1);
454 strcpy(CurrentSpeech, str);
455 err = SpeakString(c2pstr(CurrentSpeech));
456 if ( err ) {
457 PyErr_Mac(ms_error_object, err);
458 return NULL;
460 Py_INCREF(Py_None);
461 return Py_None;
465 /* Count number of available voices */
467 static PyObject *
468 ms_CountVoices(self, args)
469 PyObject *self; /* Not used */
470 PyObject *args;
472 short result;
474 if (!PyArg_NoArgs(args))
475 return NULL;
476 if ( !check_available())
477 return NULL;
478 CountVoices(&result);
479 return PyInt_FromLong(result);
482 static PyObject *
483 ms_GetIndVoice(self, args)
484 PyObject *self; /* Not used */
485 PyObject *args;
487 mvobject *rv;
488 long ind;
490 if( !PyArg_Parse(args, "i", &ind))
491 return NULL;
492 if ( !check_available() )
493 return NULL;
494 rv = newmvobject();
495 if ( !initmvobject(rv, ind) ) {
496 Py_DECREF(rv);
497 return NULL;
499 return (PyObject *)rv;
503 static PyObject *
504 ms_Version(self, args)
505 PyObject *self; /* Not used */
506 PyObject *args;
508 NumVersion v;
510 if (!PyArg_NoArgs(args))
511 return NULL;
512 if ( !check_available())
513 return NULL;
514 v = SpeechManagerVersion();
515 return PyInt_FromLong(*(int *)&v);
519 /* List of functions defined in the module */
521 static struct PyMethodDef ms_methods[] = {
522 {"Available", ms_Available},
523 {"CountVoices", ms_CountVoices},
524 {"Busy", ms_Busy},
525 {"SpeakString", ms_SpeakString},
526 {"GetIndVoice", ms_GetIndVoice},
527 {"Version", ms_Version},
528 {NULL, NULL} /* sentinel */
531 /* Initialization function for the module (*must* be called initmacspeech) */
533 void
534 initmacspeech()
536 PyObject *m, *d;
538 speech_available = init_available();
539 /* Create the module and add the functions */
540 m = Py_InitModule("macspeech", ms_methods);
542 /* Add some symbolic constants to the module */
543 d = PyModule_GetDict(m);
544 ms_error_object = PyErr_NewException("macspeech.error", NULL, NULL);
545 PyDict_SetItemString(d, "error", ms_error_object);