diff options
Diffstat (limited to 'Mac/Modules')
-rw-r--r-- | Mac/Modules/macspeech/README | 18 | ||||
-rw-r--r-- | Mac/Modules/macspeechmodule.c | 559 |
2 files changed, 577 insertions, 0 deletions
diff --git a/Mac/Modules/macspeech/README b/Mac/Modules/macspeech/README new file mode 100644 index 0000000..690a6c3 --- /dev/null +++ b/Mac/Modules/macspeech/README @@ -0,0 +1,18 @@ +To add this stuff to Macintosh python (and have some use for it): + +1. Obtain a copy of the Speech Manager. It can be found on + ftp.apple.com. +2. Put the Speech.h file from the Speech Manager distribution and + macspeechmodule.c in your python Modules directory. +3. Add the new module to python and build a new python. +4. Install the Speech Manager (under sys7 the extension goes in the + Extensions folder, the data file in the System folder) and reboot. +5. Try it. + +The test program 'hum' does that, you type notes and it hums them +(badly, addmitted, but that isn't my fault really). + +The test program 'grail' is more fun, but you need stdwin support for +it. It reads the script for the Holy Grail film from the file SCRIPT +and both animates it (text only:-) on the screen and reads it out the +speaker. It will use all voices available in the system. diff --git a/Mac/Modules/macspeechmodule.c b/Mac/Modules/macspeechmodule.c new file mode 100644 index 0000000..8e680ae --- /dev/null +++ b/Mac/Modules/macspeechmodule.c @@ -0,0 +1,559 @@ +/*********************************************************** +Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum, +Amsterdam, The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* xx module */ + +#include "allobjects.h" +#include "modsupport.h" + +#include <GestaltEqu.h> +#include "pascal.h" +#include "Speech.h" + +/* Somehow the Apple Fix2X and X2Fix don't do what I expect */ +#define fixed2double(x) (((double)(x))/32768.0) +#define double2fixed(x) ((Fixed)((x)*32768.0)) + +char *CurrentSpeech; +object *ms_error_object; + +/* General error handler */ +static object * +ms_error(num) + OSErr num; +{ + char buf[40]; + + sprintf(buf, "Mac Speech Mgr error #%d", num); + err_setstr(ms_error_object, buf); + return (object *)NULL; +} + +/* ------------- +** +** Part one - the speech channel object +*/ +typedef struct { + OB_HEAD + object *x_attr; /* Attributes dictionary */ + SpeechChannel chan; + object *curtext; /* If non-NULL current text being spoken */ +} scobject; + +staticforward typeobject sctype; + +#define is_scobject(v) ((v)->ob_type == &sctype) + +static scobject * +newscobject(arg) + VoiceSpec *arg; +{ + scobject *xp; + OSErr err; + + xp = NEWOBJ(scobject, &sctype); + if (xp == NULL) + return NULL; + xp->x_attr = NULL; + if ( (err=NewSpeechChannel(arg, &xp->chan)) != 0) { + DECREF(xp); + return (scobject *)ms_error(err); + } + xp->curtext = NULL; + return xp; +} + +/* sc methods */ + +static void +sc_dealloc(xp) + scobject *xp; +{ + DisposeSpeechChannel(xp->chan); + XDECREF(xp->x_attr); + DEL(xp); +} + +static object * +sc_Stop(self, args) + scobject *self; + object *args; +{ + OSErr err; + + if (!getnoarg(args)) + return NULL; + if ((err=StopSpeech(self->chan)) != 0) + return ms_error(err); + if ( self->curtext ) { + DECREF(self->curtext); + self->curtext = NULL; + } + INCREF(None); + return None; +} + +static object * +sc_SpeakText(self, args) + scobject *self; + object *args; +{ + OSErr err; + char *str; + int len; + + if (!getargs(args, "s#", &str, &len)) + return NULL; + if ( self->curtext ) { + StopSpeech(self->chan); + DECREF(self->curtext); + self->curtext = NULL; + } + if ((err=SpeakText(self->chan, (Ptr)str, (long)len)) != 0) + return ms_error(err); + (void)getargs(args, "O", &self->curtext); /* Or should I check this? */ + INCREF(self->curtext); + INCREF(None); + return None; +} + +static object * +sc_GetRate(self, args) + scobject *self; + object *args; +{ + OSErr err; + Fixed farg; + + if (!getnoarg(args)) + return NULL; + if ((err=GetSpeechRate(self->chan, &farg)) != 0) + return ms_error(err); + return newfloatobject(fixed2double(farg)); +} + +static object * +sc_GetPitch(self, args) + scobject *self; + object *args; +{ + OSErr err; + Fixed farg; + + if (!getnoarg(args)) + return NULL; + if ((err=GetSpeechPitch(self->chan, &farg)) != 0) + return ms_error(err); + return newfloatobject(fixed2double(farg)); +} + +static object * +sc_SetRate(self, args) + scobject *self; + object *args; +{ + OSErr err; + double darg; + + if (!getargs(args, "d", &darg)) + return NULL; + if ((err=SetSpeechRate(self->chan, double2fixed(darg))) != 0) + return ms_error(err); + INCREF(None); + return None; +} + +static object * +sc_SetPitch(self, args) + scobject *self; + object *args; +{ + OSErr err; + double darg; + + if (!getargs(args, "d", &darg)) + return NULL; + if ((err=SetSpeechPitch(self->chan, double2fixed(darg))) != 0) + return ms_error(err); + INCREF(None); + return None; +} + +static struct methodlist sc_methods[] = { + {"Stop", (method)sc_Stop}, + {"SetRate", (method)sc_SetRate}, + {"GetRate", (method)sc_GetRate}, + {"SetPitch", (method)sc_SetPitch}, + {"GetPitch", (method)sc_GetPitch}, + {"SpeakText", (method)sc_SpeakText}, + {NULL, NULL} /* sentinel */ +}; + +static object * +sc_getattr(xp, name) + scobject *xp; + char *name; +{ + if (xp->x_attr != NULL) { + object *v = dictlookup(xp->x_attr, name); + if (v != NULL) { + INCREF(v); + return v; + } + } + return findmethod(sc_methods, (object *)xp, name); +} + +static int +sc_setattr(xp, name, v) + scobject *xp; + char *name; + object *v; +{ + if (xp->x_attr == NULL) { + xp->x_attr = newdictobject(); + if (xp->x_attr == NULL) + return -1; + } + if (v == NULL) { + int rv = dictremove(xp->x_attr, name); + if (rv < 0) + err_setstr(AttributeError, + "delete non-existing sc attribute"); + return rv; + } + else + return dictinsert(xp->x_attr, name, v); +} + +static typeobject sctype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "MacSpeechChannel", /*tp_name*/ + sizeof(scobject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)sc_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)sc_getattr, /*tp_getattr*/ + (setattrfunc)sc_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +}; + +/* ------------- +** +** Part two - the voice object +*/ +typedef struct { + OB_HEAD + object *x_attr; /* Attributes dictionary */ + int initialized; + VoiceSpec vs; + VoiceDescription vd; +} mvobject; + +staticforward typeobject mvtype; + +#define is_mvobject(v) ((v)->ob_type == &mvtype) + +static mvobject * +newmvobject() +{ + mvobject *xp; + xp = NEWOBJ(mvobject, &mvtype); + if (xp == NULL) + return NULL; + xp->x_attr = NULL; + xp->initialized = 0; + return xp; +} + +static int +initmvobject(self, ind) + mvobject *self; + int ind; +{ + OSErr err; + + if ( (err=GetIndVoice((short)ind, &self->vs)) != 0 ) { + ms_error(err); + return 0; + } + if ( (err=GetVoiceDescription(&self->vs, &self->vd, sizeof self->vd)) != 0) { + ms_error(err); + return 0; + } + self->initialized = 1; + return 1; +} +/* mv methods */ + +static void +mv_dealloc(xp) + mvobject *xp; +{ + XDECREF(xp->x_attr); + DEL(xp); +} + +static object * +mv_getgender(self, args) + mvobject *self; + object *args; +{ + object *rv; + + if (!getnoarg(args)) + return NULL; + if (!self->initialized) { + err_setstr(ms_error_object, "Uninitialized voice"); + return NULL; + } + rv = newintobject(self->vd.gender); + return rv; +} + +static object * +mv_newchannel(self, args) + mvobject *self; + object *args; +{ + if (!getnoarg(args)) + return NULL; + if (!self->initialized) { + err_setstr(ms_error_object, "Uninitialized voice"); + return NULL; + } + return (object *)newscobject(&self->vs); +} + +static struct methodlist mv_methods[] = { + {"GetGender", (method)mv_getgender}, + {"NewChannel", (method)mv_newchannel}, + {NULL, NULL} /* sentinel */ +}; + +static object * +mv_getattr(xp, name) + mvobject *xp; + char *name; +{ + if (xp->x_attr != NULL) { + object *v = dictlookup(xp->x_attr, name); + if (v != NULL) { + INCREF(v); + return v; + } + } + return findmethod(mv_methods, (object *)xp, name); +} + +static int +mv_setattr(xp, name, v) + mvobject *xp; + char *name; + object *v; +{ + if (xp->x_attr == NULL) { + xp->x_attr = newdictobject(); + if (xp->x_attr == NULL) + return -1; + } + if (v == NULL) { + int rv = dictremove(xp->x_attr, name); + if (rv < 0) + err_setstr(AttributeError, + "delete non-existing MacVoice attribute"); + return rv; + } + else + return dictinsert(xp->x_attr, name, v); +} + +static typeobject mvtype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "MacVoice", /*tp_name*/ + sizeof(mvobject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)mv_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)mv_getattr, /*tp_getattr*/ + (setattrfunc)mv_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +}; + + +/* ------------- +** +** Part three - The module interface +*/ + +/* See if Speech manager available */ + +static object * +ms_Available(self, args) + object *self; /* Not used */ + object *args; +{ + OSErr err; + long result; + + if (!getnoarg(args)) + return NULL; + err = Gestalt(gestaltSpeechAttr, &result); + if ( err == noErr && (result & (1<<gestaltSpeechMgrPresent))) + result = 1; + else + result = 0; + return newintobject(result); +} + +/* Count number of busy speeches */ + +static object * +ms_Busy(self, args) + object *self; /* Not used */ + object *args; +{ + OSErr err; + short result; + + if (!getnoarg(args)) + return NULL; + result = SpeechBusy(); + return newintobject(result); +} + +/* Say something */ + +static object * +ms_SpeakString(self, args) + object *self; /* Not used */ + object *args; +{ + OSErr err; + short result; + char *str; + int len; + + if (!getstrarg(args, &str)) + return NULL; + if (CurrentSpeech) { + /* Free the old speech, after killing it off + ** (note that speach is async and c2pstr works inplace) + */ + SpeakString("\p"); + free(CurrentSpeech); + } + len = strlen(str); + CurrentSpeech = malloc(len+1); + strcpy(CurrentSpeech, str); + err = SpeakString(c2pstr(CurrentSpeech)); + if ( err ) + return ms_error(err); + INCREF(None); + return None; +} + + +/* Count number of available voices */ + +static object * +ms_CountVoices(self, args) + object *self; /* Not used */ + object *args; +{ + OSErr err; + short result; + + if (!getnoarg(args)) + return NULL; + CountVoices(&result); + return newintobject(result); +} + +static object * +ms_GetIndVoice(self, args) + object *self; /* Not used */ + object *args; +{ + OSErr err; + mvobject *rv; + long ind; + + if( !getargs(args, "i", &ind)) + return 0; + rv = newmvobject(); + if ( !initmvobject(rv, ind) ) { + DECREF(rv); + return NULL; + } + return (object *)rv; +} + + + +/* List of functions defined in the module */ + +static struct methodlist ms_methods[] = { + {"Available", ms_Available}, + {"CountVoices", ms_CountVoices}, + {"Busy", ms_Busy}, + {"SpeakString", ms_SpeakString}, + {"GetIndVoice", ms_GetIndVoice}, + {NULL, NULL} /* sentinel */ +}; + + +/* Initialization function for the module (*must* be called initmacspeech) */ + +void +initmacspeech() +{ + object *m, *d; + + /* Create the module and add the functions */ + m = initmodule("macspeech", ms_methods); + + /* Add some symbolic constants to the module */ + d = getmoduledict(m); + ms_error_object = newstringobject("macspeech.error"); + dictinsert(d, "error", ms_error_object); + + /* Check for errors */ + if (err_occurred()) + fatal("can't initialize module macspeech"); +} |