mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 10:26:02 +00:00 
			
		
		
		
	 938ace69a0
			
		
	
	
		938ace69a0
		
	
	
	
	
		
			
			The staticforward define was needed to support certain broken C compilers (notably SCO ODT 3.0, perhaps early AIX as well) botched the static keyword when it was used with a forward declaration of a static initialized structure. Standard C allows the forward declaration with static, and we've decided to stop catering to broken C compilers. (In fact, we expect that the compilers are all fixed eight years later.) I'm leaving staticforward and statichere defined in object.h as static. This is only for backwards compatibility with C extensions that might still use it. XXX I haven't updated the documentation.
		
			
				
	
	
		
			546 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			546 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /***********************************************************
 | |
| Copyright 1991-1997 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.
 | |
| 
 | |
| ******************************************************************/
 | |
| 
 | |
| 
 | |
| #include "Python.h"
 | |
| #include "macglue.h"
 | |
| 
 | |
| #include <Gestalt.h>
 | |
| #include "Speech.h"
 | |
| 
 | |
| #ifdef __MWERKS__
 | |
| #define OLDP2C 1
 | |
| #include <TextUtils.h>
 | |
| #ifndef c2pstr
 | |
| #define c2pstr C2PStr
 | |
| #endif
 | |
| #ifndef p2cstr
 | |
| #define p2cstr P2CStr
 | |
| #endif
 | |
| #else
 | |
| #include "pascal.h"
 | |
| #endif /* __MWERKS__ */
 | |
| 
 | |
| #include <CodeFragments.h>
 | |
| int lib_available;
 | |
| 
 | |
| /* 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;
 | |
| PyObject *ms_error_object;
 | |
| int speech_available;
 | |
| 
 | |
| static
 | |
| init_available() {
 | |
| 	OSErr err;
 | |
| 	long result;
 | |
| 
 | |
| 	lib_available = ((ProcPtr)SpeakString != (ProcPtr)0);
 | |
| 	err = Gestalt(gestaltSpeechAttr, &result);
 | |
| 	if ( err == noErr && (result & (1<<gestaltSpeechMgrPresent)))
 | |
| 		return 1;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static
 | |
| check_available() {
 | |
| 	if ( !speech_available ) {
 | |
| 		PyErr_SetString(ms_error_object, "Speech Mgr not available");
 | |
| 		return 0;
 | |
| 	}
 | |
| 	if ( !lib_available ) {
 | |
| 		PyErr_SetString(ms_error_object, "Speech Mgr available, but shared lib missing");
 | |
| 		return 0;
 | |
| 	}
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| /* -------------
 | |
| **
 | |
| ** Part one - the speech channel object
 | |
| */
 | |
| typedef struct {
 | |
| 	PyObject_HEAD
 | |
| 	SpeechChannel chan;
 | |
| 	PyObject *curtext;	/* If non-NULL current text being spoken */
 | |
| } scobject;
 | |
| 
 | |
| static PyTypeObject sctype;
 | |
| 
 | |
| #define is_scobject(v)		((v)->ob_type == &sctype)
 | |
| 
 | |
| static scobject *
 | |
| newscobject(arg)
 | |
| 	VoiceSpec *arg;
 | |
| {
 | |
| 	scobject *self;
 | |
| 	OSErr err;
 | |
| 	
 | |
| 	self = PyObject_NEW(scobject, &sctype);
 | |
| 	if (self == NULL)
 | |
| 		return NULL;
 | |
| 	if ( (err=NewSpeechChannel(arg, &self->chan)) != 0) {
 | |
| 		Py_DECREF(self);
 | |
| 		return (scobject *)PyErr_Mac(ms_error_object, err);
 | |
| 	}
 | |
| 	self->curtext = NULL;
 | |
| 	return self;
 | |
| }
 | |
| 
 | |
| /* sc methods */
 | |
| 
 | |
| static void
 | |
| sc_dealloc(self)
 | |
| 	scobject *self;
 | |
| {
 | |
| 	DisposeSpeechChannel(self->chan);
 | |
| 	PyObject_DEL(self);
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| sc_Stop(self, args)
 | |
| 	scobject *self;
 | |
| 	PyObject *args;
 | |
| {
 | |
| 	OSErr err;
 | |
| 	
 | |
| 	if (!PyArg_NoArgs(args))
 | |
| 		return NULL;
 | |
| 	if ((err=StopSpeech(self->chan)) != 0) {
 | |
| 		PyErr_Mac(ms_error_object, err);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	if ( self->curtext ) {
 | |
| 		Py_DECREF(self->curtext);
 | |
| 		self->curtext = NULL;
 | |
| 	}
 | |
| 	Py_INCREF(Py_None);
 | |
| 	return Py_None;
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| sc_SpeakText(self, args)
 | |
| 	scobject *self;
 | |
| 	PyObject *args;
 | |
| {
 | |
| 	OSErr err;
 | |
| 	char *str;
 | |
| 	int len;
 | |
| 	
 | |
| 	if (!PyArg_Parse(args, "s#", &str, &len))
 | |
| 		return NULL;
 | |
| 	if ( self->curtext ) {
 | |
| 		StopSpeech(self->chan);
 | |
| 		Py_DECREF(self->curtext);
 | |
| 		self->curtext = NULL;
 | |
| 	}
 | |
| 	if ((err=SpeakText(self->chan, (Ptr)str, (long)len)) != 0) {
 | |
| 		PyErr_Mac(ms_error_object, err);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	(void)PyArg_Parse(args, "O", &self->curtext);	/* Or should I check this? */
 | |
| 	Py_INCREF(self->curtext);
 | |
| 	Py_INCREF(Py_None);
 | |
| 	return Py_None;
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| sc_GetRate(self, args)
 | |
| 	scobject *self;
 | |
| 	PyObject *args;
 | |
| {
 | |
| 	OSErr err;
 | |
| 	Fixed farg;
 | |
| 	
 | |
| 	if (!PyArg_NoArgs(args))
 | |
| 		return NULL;
 | |
| 	if ((err=GetSpeechRate(self->chan, &farg)) != 0) {
 | |
| 		PyErr_Mac(ms_error_object, err);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	return PyFloat_FromDouble(fixed2double(farg));
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| sc_GetPitch(self, args)
 | |
| 	scobject *self;
 | |
| 	PyObject *args;
 | |
| {
 | |
| 	OSErr err;
 | |
| 	Fixed farg;
 | |
| 	
 | |
| 	if (!PyArg_NoArgs(args))
 | |
| 		return NULL;
 | |
| 	if ((err=GetSpeechPitch(self->chan, &farg)) != 0) {
 | |
| 		PyErr_Mac(ms_error_object, err);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	return PyFloat_FromDouble(fixed2double(farg));
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| sc_SetRate(self, args)
 | |
| 	scobject *self;
 | |
| 	PyObject *args;
 | |
| {
 | |
| 	OSErr err;
 | |
| 	double darg;
 | |
| 	
 | |
| 	if (!PyArg_Parse(args, "d", &darg))
 | |
| 		return NULL;
 | |
| 	if ((err=SetSpeechRate(self->chan, double2fixed(darg))) != 0) {
 | |
| 		PyErr_Mac(ms_error_object, err);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	Py_INCREF(Py_None);
 | |
| 	return Py_None;
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| sc_SetPitch(self, args)
 | |
| 	scobject *self;
 | |
| 	PyObject *args;
 | |
| {
 | |
| 	OSErr err;
 | |
| 	double darg;
 | |
| 	
 | |
| 	if (!PyArg_Parse(args, "d", &darg))
 | |
| 		return NULL;
 | |
| 	if ((err=SetSpeechPitch(self->chan, double2fixed(darg))) != 0) {
 | |
| 		PyErr_Mac(ms_error_object, err);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	Py_INCREF(Py_None);
 | |
| 	return Py_None;
 | |
| }
 | |
| 
 | |
| static struct PyMethodDef sc_methods[] = {
 | |
| 	{"Stop",		(PyCFunction)sc_Stop},
 | |
| 	{"SetRate",		(PyCFunction)sc_SetRate},
 | |
| 	{"GetRate",		(PyCFunction)sc_GetRate},
 | |
| 	{"SetPitch",	(PyCFunction)sc_SetPitch},
 | |
| 	{"GetPitch",	(PyCFunction)sc_GetPitch},
 | |
| 	{"SpeakText",	(PyCFunction)sc_SpeakText},
 | |
| 	{NULL,			NULL}		/* sentinel */
 | |
| };
 | |
| 
 | |
| static PyObject *
 | |
| sc_getattr(self, name)
 | |
| 	scobject *self;
 | |
| 	char *name;
 | |
| {
 | |
| 	return Py_FindMethod(sc_methods, (PyObject *)self, name);
 | |
| }
 | |
| 
 | |
| static PyTypeObject sctype = {
 | |
| 	PyObject_HEAD_INIT(&PyType_Type)
 | |
| 	0,			/*ob_size*/
 | |
| 	"macspeech.MacSpeechChannel", /*tp_name*/
 | |
| 	sizeof(scobject),	/*tp_basicsize*/
 | |
| 	0,			/*tp_itemsize*/
 | |
| 	/* methods */
 | |
| 	(destructor)sc_dealloc, /*tp_dealloc*/
 | |
| 	0,			/*tp_print*/
 | |
| 	(getattrfunc)sc_getattr, /*tp_getattr*/
 | |
| 	0, 			/*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 {
 | |
| 	PyObject_HEAD
 | |
| 	int		initialized;
 | |
| 	VoiceSpec	vs;
 | |
| 	VoiceDescription vd;
 | |
| } mvobject;
 | |
| 
 | |
| static PyTypeObject mvtype;
 | |
| 
 | |
| #define is_mvobject(v)		((v)->ob_type == &mvtype)
 | |
| 
 | |
| static mvobject *
 | |
| newmvobject()
 | |
| {
 | |
| 	mvobject *self;
 | |
| 	self = PyObject_NEW(mvobject, &mvtype);
 | |
| 	if (self == NULL)
 | |
| 		return NULL;
 | |
| 	self->initialized = 0;
 | |
| 	return self;
 | |
| }
 | |
| 
 | |
| static int
 | |
| initmvobject(self, ind)
 | |
| 	mvobject *self;
 | |
| 	int ind;
 | |
| {
 | |
| 	OSErr err;
 | |
| 	
 | |
| 	if ( (err=GetIndVoice((short)ind, &self->vs)) != 0 ) {
 | |
| 		PyErr_Mac(ms_error_object, err);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	if ( (err=GetVoiceDescription(&self->vs, &self->vd, sizeof self->vd)) != 0) {
 | |
| 		PyErr_Mac(ms_error_object, err);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	self->initialized = 1;
 | |
| 	return 1;
 | |
| } 
 | |
| /* mv methods */
 | |
| 
 | |
| static void
 | |
| mv_dealloc(self)
 | |
| 	mvobject *self;
 | |
| {
 | |
| 	PyObject_DEL(self);
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| mv_getgender(self, args)
 | |
| 	mvobject *self;
 | |
| 	PyObject *args;
 | |
| {
 | |
| 	PyObject *rv;
 | |
| 	
 | |
| 	if (!PyArg_NoArgs(args))
 | |
| 		return NULL;
 | |
| 	if (!self->initialized) {
 | |
| 		PyErr_SetString(ms_error_object, "Uninitialized voice");
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	rv = PyInt_FromLong(self->vd.gender);
 | |
| 	return rv;
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| mv_newchannel(self, args)
 | |
| 	mvobject *self;
 | |
| 	PyObject *args;
 | |
| {	
 | |
| 	if (!PyArg_NoArgs(args))
 | |
| 		return NULL;
 | |
| 	if (!self->initialized) {
 | |
| 		PyErr_SetString(ms_error_object, "Uninitialized voice");
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	return (PyObject *)newscobject(&self->vs);
 | |
| }
 | |
| 
 | |
| static struct PyMethodDef mv_methods[] = {
 | |
| 	{"GetGender",	(PyCFunction)mv_getgender},
 | |
| 	{"NewChannel",	(PyCFunction)mv_newchannel},
 | |
| 	{NULL,		NULL}		/* sentinel */
 | |
| };
 | |
| 
 | |
| static PyObject *
 | |
| mv_getattr(self, name)
 | |
| 	mvobject *self;
 | |
| 	char *name;
 | |
| {
 | |
| 	return Py_FindMethod(mv_methods, (PyObject *)self, name);
 | |
| }
 | |
| 
 | |
| static PyTypeObject mvtype = {
 | |
| 	PyObject_HEAD_INIT(&PyType_Type)
 | |
| 	0,			/*ob_size*/
 | |
| 	"macspeech.MacVoice",	/*tp_name*/
 | |
| 	sizeof(mvobject),	/*tp_basicsize*/
 | |
| 	0,			/*tp_itemsize*/
 | |
| 	/* methods */
 | |
| 	(destructor)mv_dealloc, /*tp_dealloc*/
 | |
| 	0,			/*tp_print*/
 | |
| 	(getattrfunc)mv_getattr, /*tp_getattr*/
 | |
| 	0,			/*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 PyObject *
 | |
| ms_Available(self, args)
 | |
| 	PyObject *self; /* Not used */
 | |
| 	PyObject *args;
 | |
| {
 | |
| 	
 | |
| 	if (!PyArg_NoArgs(args))
 | |
| 		return NULL;
 | |
| 	return PyInt_FromLong(speech_available);
 | |
| }
 | |
| 
 | |
| /* Count number of busy speeches */
 | |
| 
 | |
| static PyObject *
 | |
| ms_Busy(self, args)
 | |
| 	PyObject *self; /* Not used */
 | |
| 	PyObject *args;
 | |
| {
 | |
| 	short result;
 | |
| 	
 | |
| 	if (!PyArg_NoArgs(args))
 | |
| 		return NULL;
 | |
| 	if ( !check_available() )
 | |
| 		return NULL;
 | |
| 	result = SpeechBusy();
 | |
| 	return PyInt_FromLong(result);
 | |
| }
 | |
| 
 | |
| /* Say something */
 | |
| 
 | |
| static PyObject *
 | |
| ms_SpeakString(self, args)
 | |
| 	PyObject *self; /* Not used */
 | |
| 	PyObject *args;
 | |
| {
 | |
| 	OSErr err;
 | |
| 	char *str;
 | |
| 	int len;
 | |
| 	
 | |
| 	if (!PyArg_Parse(args, "s", &str))
 | |
| 		return NULL;
 | |
| 	if ( !check_available())
 | |
| 		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 ) {
 | |
| 		PyErr_Mac(ms_error_object, err);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	Py_INCREF(Py_None);
 | |
| 	return Py_None;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Count number of available voices */
 | |
| 
 | |
| static PyObject *
 | |
| ms_CountVoices(self, args)
 | |
| 	PyObject *self; /* Not used */
 | |
| 	PyObject *args;
 | |
| {
 | |
| 	short result;
 | |
| 	
 | |
| 	if (!PyArg_NoArgs(args))
 | |
| 		return NULL;
 | |
| 	if ( !check_available())
 | |
| 		return NULL;
 | |
| 	CountVoices(&result);
 | |
| 	return PyInt_FromLong(result);
 | |
| }
 | |
| 
 | |
| static PyObject *
 | |
| ms_GetIndVoice(self, args)
 | |
| 	PyObject *self; /* Not used */
 | |
| 	PyObject *args;
 | |
| {
 | |
| 	mvobject *rv;
 | |
| 	long ind;
 | |
| 	
 | |
| 	if( !PyArg_Parse(args, "i", &ind))
 | |
| 		return NULL;
 | |
| 	if ( !check_available() )
 | |
| 		return NULL;
 | |
| 	rv = newmvobject();
 | |
| 	if ( !initmvobject(rv, ind) ) {
 | |
| 		Py_DECREF(rv);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	return (PyObject *)rv;
 | |
| }
 | |
| 
 | |
| 
 | |
| static PyObject *
 | |
| ms_Version(self, args)
 | |
| 	PyObject *self; /* Not used */
 | |
| 	PyObject *args;
 | |
| {
 | |
| 	NumVersion v;
 | |
| 	
 | |
| 	if (!PyArg_NoArgs(args))
 | |
| 		return NULL;
 | |
| 	if ( !check_available())
 | |
| 		return NULL;
 | |
| 	v = SpeechManagerVersion();
 | |
| 	return PyInt_FromLong(*(int *)&v);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* List of functions defined in the module */
 | |
| 
 | |
| static struct PyMethodDef ms_methods[] = {
 | |
| 	{"Available",	ms_Available},
 | |
| 	{"CountVoices",	ms_CountVoices},
 | |
| 	{"Busy",		ms_Busy},
 | |
| 	{"SpeakString",	ms_SpeakString},
 | |
| 	{"GetIndVoice", ms_GetIndVoice},
 | |
| 	{"Version",		ms_Version},
 | |
| 	{NULL,		NULL}		/* sentinel */
 | |
| };
 | |
| 
 | |
| /* Initialization function for the module (*must* be called initmacspeech) */
 | |
| 
 | |
| void
 | |
| initmacspeech()
 | |
| {
 | |
| 	PyObject *m, *d;
 | |
| 
 | |
| 	speech_available = init_available();
 | |
| 	/* Create the module and add the functions */
 | |
| 	m = Py_InitModule("macspeech", ms_methods);
 | |
| 
 | |
| 	/* Add some symbolic constants to the module */
 | |
| 	d = PyModule_GetDict(m);
 | |
| 	ms_error_object = PyErr_NewException("macspeech.error", NULL, NULL);
 | |
| 	PyDict_SetItemString(d, "error", ms_error_object);
 | |
| }
 |