| /*********************************************************** |
| Copyright 1991-1995 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. |
| |
| ******************************************************************/ |
| |
| /* Macintosh OS-specific interface */ |
| |
| #include "Python.h" |
| #include "macglue.h" |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <errno.h> |
| |
| #include <OSUtils.h> /* for Set(Current)A5 */ |
| #include <Resources.h> |
| #include <Memory.h> |
| #include <Sound.h> |
| |
| #ifndef __MWERKS__ |
| #define SndCallBackUPP ProcPtr |
| #define NewSndCallBackProc(x) (x) |
| #endif |
| |
| /*----------------------------------------------------------------------*/ |
| /* General tools */ |
| |
| static PyObject *MacOS_Error; /* Exception MacOS.Error */ |
| |
| /* Convert a ResType argument */ |
| static int |
| GetOSType(PyObject *v, ResType *pr) |
| { |
| if (!PyString_Check(v) || PyString_Size(v) != 4) { |
| PyErr_SetString(MacOS_Error, |
| "OSType arg must be string of 4 chars"); |
| return 0; |
| } |
| memcpy((char *)pr, PyString_AsString(v), 4); |
| return 1; |
| } |
| |
| /* Convert a Str255 argument */ |
| static int |
| GetStr255(PyObject *v, Str255 pbuf) |
| { |
| int len; |
| if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) { |
| PyErr_SetString(MacOS_Error, |
| "Str255 arg must be string of at most 255 chars"); |
| return 0; |
| } |
| pbuf[0] = len; |
| memcpy((char *)(pbuf+1), PyString_AsString(v), len); |
| return 1; |
| } |
| |
| /*----------------------------------------------------------------------*/ |
| /* Resource objects */ |
| |
| typedef struct { |
| OB_HEAD |
| Handle h; |
| } RsrcObject; |
| |
| staticforward PyTypeObject RsrcType; |
| |
| #define Rsrc_Check(r) ((r)->ob_type == &RsrcType) |
| |
| static RsrcObject * |
| Rsrc_FromHandle(Handle h) |
| { |
| RsrcObject *r; |
| if (h == NULL) |
| return (RsrcObject *)PyErr_Mac(MacOS_Error, (int)ResError()); |
| r = PyObject_NEW(RsrcObject, &RsrcType); |
| if (r != NULL) |
| r->h = h; |
| return r; |
| } |
| |
| static void |
| Rsrc_Dealloc(RsrcObject *r) |
| { |
| /* XXXX Note by Jack: shouldn't we ReleaseResource here? */ |
| PyMem_DEL(r); |
| } |
| |
| static PyObject * |
| Rsrc_GetResInfo(RsrcObject *r, PyObject *args) |
| { |
| short id; |
| ResType type; |
| Str255 name; |
| if (!PyArg_Parse(args, "()")) |
| return NULL; |
| GetResInfo(r->h, &id, &type, name); |
| return Py_BuildValue("(is#s#)", |
| (int)id, (char *)&type, 4, name+1, (int)name[0]); |
| } |
| |
| static PyObject * |
| Rsrc_AsBytes(RsrcObject *r, PyObject *args) |
| { |
| long len; |
| PyObject *rv; |
| char *cp; |
| |
| if (!PyArg_Parse(args, "(l)", &len)) |
| return NULL; |
| HLock(r->h); |
| cp = (char *)*r->h; |
| rv = PyString_FromStringAndSize(cp, len); |
| HUnlock(r->h); |
| return rv; |
| } |
| |
| static PyObject * |
| Rsrc_AsString(RsrcObject *r, PyObject *args) |
| { |
| PyObject *rv; |
| unsigned char *cp; |
| |
| if (!PyArg_Parse(args, "()")) |
| return NULL; |
| HLock(r->h); |
| cp = (unsigned char *)*r->h; |
| rv = PyString_FromStringAndSize((char *)cp+1, cp[0]); |
| HUnlock(r->h); |
| return rv; |
| } |
| |
| static PyMethodDef Rsrc_Methods[] = { |
| {"GetResInfo", (PyCFunction)Rsrc_GetResInfo, 1}, |
| {"AsString", (PyCFunction)Rsrc_AsString, 1}, |
| {"AsBytes", (PyCFunction)Rsrc_AsBytes, 1}, |
| {NULL, NULL} /* Sentinel */ |
| }; |
| |
| static PyObject * |
| Rsrc_GetAttr(PyObject *r, char *name) |
| { |
| return Py_FindMethod(Rsrc_Methods, r, name); |
| } |
| |
| static PyTypeObject RsrcType = { |
| PyObject_HEAD_INIT(&PyType_Type) |
| 0, |
| "Resource", /*tp_name*/ |
| sizeof(RsrcObject), /*tp_basicsize*/ |
| 0, /*tp_itemsize*/ |
| /* methods */ |
| (destructor)Rsrc_Dealloc, /*tp_dealloc*/ |
| 0, /*tp_print*/ |
| (getattrfunc)Rsrc_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*/ |
| }; |
| |
| static PyObject * |
| MacOS_GetResource(PyObject *self, PyObject *args) |
| { |
| ResType rt; |
| int id; |
| Handle h; |
| if (!PyArg_Parse(args, "(O&i)", GetOSType, &rt, &id)) |
| return NULL; |
| h = GetResource(rt, id); |
| return (PyObject *)Rsrc_FromHandle(h); |
| } |
| |
| static PyObject * |
| MacOS_GetNamedResource(PyObject *self, PyObject *args) |
| { |
| ResType rt; |
| Str255 name; |
| Handle h; |
| if (!PyArg_Parse(args, "(O&O&)", GetOSType, &rt, GetStr255, &name)) |
| return NULL; |
| h = GetNamedResource(rt, name); |
| return (PyObject *)Rsrc_FromHandle(h); |
| } |
| |
| /*----------------------------------------------------------------------*/ |
| /* SoundChannel objects */ |
| |
| /* Convert a SndCommand argument */ |
| static int |
| GetSndCommand(PyObject *v, SndCommand *pc) |
| { |
| int len; |
| pc->param1 = 0; |
| pc->param2 = 0; |
| if (PyArg_Parse(v, "h", &pc->cmd)) |
| return 1; |
| PyErr_Clear(); |
| if (PyArg_Parse(v, "(h)", &pc->cmd)) |
| return 1; |
| PyErr_Clear(); |
| if (PyArg_Parse(v, "(hh)", &pc->cmd, &pc->param1)) |
| return 1; |
| PyErr_Clear(); |
| if (PyArg_Parse(v, "(hhl)", |
| &pc->cmd, &pc->param1, &pc->param2)) |
| return 1; |
| PyErr_Clear(); |
| if (PyArg_Parse(v, "(hhs#);SndCommand arg must be 1-3 ints or 2 ints + string", |
| &pc->cmd, &pc->param1, &pc->param2, &len)) |
| return 1; |
| return 0; |
| } |
| |
| typedef struct { |
| OB_HEAD |
| SndChannelPtr chan; |
| } SndChObject; |
| |
| staticforward PyTypeObject SndChType; |
| |
| #define SndCh_Check(s) ((s)->ob_type == &SndChType) |
| |
| static SndChObject * |
| SndCh_FromSndChannelPtr(SndChannelPtr chan) |
| { |
| SndChObject *s = PyObject_NEW(SndChObject, &SndChType); |
| if (s != NULL) |
| s->chan = chan; |
| return s; |
| } |
| |
| static void |
| SndCh_Cleanup(SndChObject *s, int quitNow) |
| { |
| SndChannelPtr chan = s->chan; |
| if (chan != NULL) { |
| void *userInfo = (void *)chan->userInfo; |
| s->chan = NULL; |
| SndDisposeChannel(chan, quitNow); |
| if (userInfo != 0) |
| DEL(userInfo); |
| } |
| } |
| |
| static void |
| SndCh_Dealloc(SndChObject *s) |
| { |
| SndCh_Cleanup(s, 1); |
| PyMem_DEL(s); |
| } |
| |
| static PyObject * |
| SndCh_DisposeChannel(SndChObject *s, PyObject *args) |
| { |
| int quitNow = 1; |
| if (PyTuple_Size(args) > 0) { |
| if (!PyArg_Parse(args, "(i)", &quitNow)) |
| return NULL; |
| } |
| SndCh_Cleanup(s, quitNow); |
| Py_INCREF(Py_None); |
| return Py_None; |
| } |
| |
| static int |
| SndCh_OK(SndChObject *s) |
| { |
| if (s->chan == NULL) { |
| PyErr_SetString(MacOS_Error, "channel is closed"); |
| return 0; |
| } |
| return 1; |
| } |
| |
| static PyObject * |
| SndCh_SndPlay(SndChObject *s, PyObject *args) |
| { |
| RsrcObject *r; |
| int async = 0; |
| if (!PyArg_Parse(args, "(O!)", RsrcType, &r)) { |
| PyErr_Clear(); |
| if (!PyArg_Parse(args, "(O&i)", RsrcType, &r, &async)) |
| return NULL; |
| } |
| if (!SndCh_OK(s)) |
| return NULL; |
| SndPlay(s->chan, r->h, async); |
| Py_INCREF(Py_None); |
| return Py_None; |
| } |
| |
| static PyObject * |
| SndCh_SndDoCommand(SndChObject *s, PyObject *args) |
| { |
| SndCommand c; |
| int noWait = 0; |
| OSErr err; |
| if (!PyArg_Parse(args, "(O&)", GetSndCommand, &c)) { |
| PyErr_Clear(); |
| if (!PyArg_Parse(args, "(O&i)", GetSndCommand, &c, &noWait)) |
| return NULL; |
| } |
| if (!SndCh_OK(s)) |
| return NULL; |
| err = SndDoCommand(s->chan, &c, noWait); |
| return PyErr_Mac(MacOS_Error, (int)err); |
| } |
| |
| static PyObject * |
| SndCh_SndDoImmediate(SndChObject *s, PyObject *args) |
| { |
| SndCommand c; |
| OSErr err; |
| if (!PyArg_Parse(args, "(O&)", GetSndCommand, &c)) |
| return 0; |
| if (!SndCh_OK(s)) |
| return NULL; |
| err = SndDoImmediate(s->chan, &c); |
| return PyErr_Mac(MacOS_Error, (int)err); |
| } |
| |
| static PyMethodDef SndCh_Methods[] = { |
| {"close", (PyCFunction)SndCh_DisposeChannel, 1}, |
| {"SndDisposeChannel", (PyCFunction)SndCh_DisposeChannel, 1}, |
| {"SndPlay", (PyCFunction)SndCh_SndPlay, 1}, |
| {"SndDoCommand", (PyCFunction)SndCh_SndDoCommand, 1}, |
| {"SndDoImmediate", (PyCFunction)SndCh_SndDoImmediate, 1}, |
| {NULL, NULL} /* Sentinel */ |
| }; |
| |
| static PyObject * |
| SndCh_GetAttr(PyObject *s, char *name) |
| { |
| return Py_FindMethod(SndCh_Methods, s, name); |
| } |
| |
| static PyTypeObject SndChType = { |
| PyObject_HEAD_INIT(&PyType_Type) |
| 0, |
| "SoundChannel", /*tp_name*/ |
| sizeof(SndChObject), /*tp_basicsize*/ |
| 0, /*tp_itemsize*/ |
| /* methods */ |
| (destructor)SndCh_Dealloc, /*tp_dealloc*/ |
| 0, /*tp_print*/ |
| (getattrfunc)SndCh_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*/ |
| }; |
| |
| /*----------------------------------------------------------------------*/ |
| /* Module */ |
| |
| typedef struct { |
| long A5; |
| PyObject *callback; |
| PyObject *channel; |
| SndCommand cmd; |
| } cbinfo; |
| |
| static int |
| MySafeCallback(arg) |
| void *arg; |
| { |
| cbinfo *p = (cbinfo *)arg; |
| PyObject *args; |
| PyObject *res; |
| args = Py_BuildValue("(O(hhl))", |
| p->channel, p->cmd.cmd, p->cmd.param1, p->cmd.param2); |
| res = PyEval_CallObject(p->callback, args); |
| Py_DECREF(args); |
| if (res == NULL) |
| return -1; |
| DECREF(res); |
| return 0; |
| } |
| |
| static pascal void |
| #ifdef __MWERKS__ |
| MyUserRoutine(SndChannelPtr chan, SndCommand *cmd) |
| #else |
| MyUserRoutine(SndChannelPtr chan, SndCommand cmd) |
| #endif |
| { |
| cbinfo *p = (cbinfo *)chan->userInfo; |
| long A5 = SetA5(p->A5); |
| #ifdef __MWERKS__ |
| p->cmd = *cmd; |
| #else |
| p->cmd = cmd; |
| #endif |
| Py_AddPendingCall(MySafeCallback, (void *)p); |
| SetA5(A5); |
| } |
| |
| static PyObject * |
| MacOS_SndNewChannel(PyObject *self, PyObject *args) |
| { |
| SndChannelPtr chan; |
| short synth; |
| long init = 0; |
| PyObject *callback = NULL; |
| cbinfo *p = NULL; |
| SndCallBackUPP userroutine = 0; |
| OSErr err; |
| PyObject *res; |
| if (!PyArg_Parse(args, "(h)", &synth)) { |
| PyErr_Clear(); |
| if (!PyArg_Parse(args, "(hl)", &synth, &init)) { |
| PyErr_Clear(); |
| if (!PyArg_Parse(args, "(hlO)", &synth, &init, &callback)) |
| return NULL; |
| } |
| } |
| if (callback != NULL) { |
| p = NEW(cbinfo, 1); |
| if (p == NULL) |
| return PyErr_NoMemory(); |
| p->A5 = SetCurrentA5(); |
| p->callback = callback; |
| userroutine = NewSndCallBackProc(MyUserRoutine); |
| } |
| chan = NULL; |
| err = SndNewChannel(&chan, synth, init, userroutine); |
| if (err) { |
| if (p) |
| DEL(p); |
| return PyErr_Mac(MacOS_Error, (int)err); |
| } |
| res = (PyObject *)SndCh_FromSndChannelPtr(chan); |
| if (res == NULL) { |
| SndDisposeChannel(chan, 1); |
| DEL(p); |
| } |
| else { |
| chan->userInfo = (long)p; |
| p->channel = res; |
| } |
| return res; |
| } |
| |
| static PyObject * |
| MacOS_SndPlay(PyObject *self, PyObject *args) |
| { |
| RsrcObject *r; |
| OSErr err; |
| if (!PyArg_Parse(args, "(O!)", &RsrcType, &r)) |
| return NULL; |
| err = SndPlay((SndChannelPtr)NULL, r->h, 0); |
| return PyErr_Mac(MacOS_Error, (int)err); |
| } |
| |
| static PyObject * |
| MacOS_SndControl(PyObject *self, PyObject *args) |
| { |
| int id; |
| SndCommand c; |
| OSErr err; |
| if (!PyArg_Parse(args, "(iO&)", &id, GetSndCommand, &c)) |
| return NULL; |
| err = SndControl(id, &c); |
| if (err) |
| return PyErr_Mac(MacOS_Error, (int)err); |
| return Py_BuildValue("(hhl)", c.cmd, c.param1, c.param2); |
| } |
| |
| static PyMethodDef MacOS_Methods[] = { |
| {"GetResource", MacOS_GetResource, 1}, |
| {"GetNamedResource", MacOS_GetNamedResource, 1}, |
| {"SndNewChannel", MacOS_SndNewChannel, 1}, |
| {"SndPlay", MacOS_SndPlay, 1}, |
| {"SndControl", MacOS_SndControl, 1}, |
| {NULL, NULL} /* Sentinel */ |
| }; |
| |
| |
| void |
| MacOS_Init() |
| { |
| PyObject *m, *d; |
| |
| m = Py_InitModule("MacOS", MacOS_Methods); |
| d = PyModule_GetDict(m); |
| |
| /* Initialize MacOS.Error exception */ |
| MacOS_Error = PyString_FromString("MacOS.Error"); |
| if (MacOS_Error == NULL || PyDict_SetItemString(d, "Error", MacOS_Error) != 0) |
| Py_FatalError("can't define MacOS.Error"); |
| } |