blob: 4c3f132da460056328eeb3c86b61ed9ab2357232 [file] [log] [blame]
Guido van Rossum2d167031994-09-16 10:54:21 +00001/***********************************************************
2Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
3Amsterdam, The Netherlands.
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25/* Macintosh OS-specific interface */
26
27#include "Python.h"
28
29#include <stdio.h>
30#include <string.h>
31#include <errno.h>
32
Guido van Rossumdf1c4ee1994-09-16 12:48:59 +000033#include <OSUtils.h> /* for Set(Current)A5 */
Guido van Rossum2d167031994-09-16 10:54:21 +000034#include <Resources.h>
35#include <Sound.h>
36
37/*----------------------------------------------------------------------*/
38/* General tools */
39
40static PyObject *MacOS_Error; /* Exception MacOS.Error */
41
42/* Set a MAC-specific error from errno, and return NULL; return None if no error */
43static PyObject *
44Err(OSErr err)
45{
46 char buf[100];
47 PyObject *v;
48 if (err == 0) {
49 Py_INCREF(Py_None);
50 return Py_None;
51 }
52 sprintf(buf, "Mac OS error code %d", (int)err);
53 v = Py_BuildValue("(is)", (int)err, buf);
54 PyErr_SetObject(MacOS_Error, v);
55 Py_DECREF(v);
56 return NULL;
57}
58
59/* Check for a ResType argument */
60static int
61GetOSType(PyObject *v, ResType *pr)
62{
63 if (!PyString_Check(v) || PyString_Size(v) != 4) {
64 PyErr_SetString(MacOS_Error,
65 "OSType arg must be string of 4 chars");
66 return 0;
67 }
68 memcpy((char *)pr, PyString_AsString(v), 4);
69 return 1;
70}
71
72/* Check for a Str255 argument */
73static int
74GetStr255(PyObject *v, Str255 pbuf)
75{
76 int len;
77 if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) {
78 PyErr_SetString(MacOS_Error,
79 "Str255 arg must be string <= 255 chars");
80 return 0;
81 }
82 pbuf[0] = len;
83 memcpy((char *)(pbuf+1), PyString_AsString(v), len);
84 return 1;
85}
86
87/*----------------------------------------------------------------------*/
88/* Resource objects */
89
90typedef struct {
91 OB_HEAD
92 Handle h;
93} RsrcObject;
94
95staticforward PyTypeObject RsrcType;
96
97#define RsrcObject_Check(r) ((r)->ob_type == &RsrcType)
98
99static RsrcObject *
100Rsrc_FromHandle(Handle h)
101{
102 RsrcObject *r;
103 if (h == NULL)
104 return (RsrcObject *)Err(ResError());
105 r = PyObject_NEW(RsrcObject, &RsrcType);
106 if (r != NULL)
107 r->h = h;
108 return r;
109}
110
111static void
112Rsrc_Dealloc(RsrcObject *r)
113{
114 PyMem_DEL(r);
115}
116
117static PyObject *
118Rsrc_GetResInfo(RsrcObject *r, PyObject *args)
119{
120 short id;
121 ResType type;
122 Str255 name;
123 if (!PyArg_Parse(args, "()"))
124 return NULL;
125 GetResInfo(r->h, &id, &type, name);
126 return Py_BuildValue("(is#s#)",
127 (int)id, (char *)&type, 4, name+1, (int)name[0]);
128}
129
130static PyMethodDef Rsrc_Methods[] = {
131 {"GetResInfo", (PyCFunction)Rsrc_GetResInfo, 1},
132 {NULL, NULL} /* Sentinel */
133};
134
135static PyObject *
136Rsrc_GetAttr(PyObject *r, char *name)
137{
138 return Py_FindMethod(Rsrc_Methods, r, name);
139}
140
141static PyTypeObject RsrcType = {
142 PyObject_HEAD_INIT(&PyType_Type)
143 0,
144 "Resource", /*tp_name*/
145 sizeof(RsrcObject), /*tp_basicsize*/
146 0, /*tp_itemsize*/
147 /* methods */
148 (destructor)Rsrc_Dealloc, /*tp_dealloc*/
149 0, /*tp_print*/
150 (getattrfunc)Rsrc_GetAttr, /*tp_getattr*/
151 0, /*tp_setattr*/
152 0, /*tp_compare*/
153 0, /*tp_repr*/
154 0, /*tp_as_number*/
155 0, /*tp_as_sequence*/
156 0, /*tp_as_mapping*/
157 0, /*tp_hash*/
158};
159
160static PyObject *
161MacOS_GetResource(PyObject *self, PyObject *args)
162{
163 ResType rt;
164 int id;
165 Handle h;
166 if (!PyArg_Parse(args, "(O&i)", GetOSType, &rt, &id))
167 return NULL;
168 h = GetResource(rt, id);
169 return (PyObject *)Rsrc_FromHandle(h);
170}
171
172static PyObject *
173MacOS_GetNamedResource(PyObject *self, PyObject *args)
174{
175 ResType rt;
176 Str255 name;
177 Handle h;
178 if (!PyArg_Parse(args, "(O&O&)", GetOSType, &rt, GetStr255, &name))
179 return NULL;
180 h = GetNamedResource(rt, name);
181 return (PyObject *)Rsrc_FromHandle(h);
182}
183
184/*----------------------------------------------------------------------*/
185/* SoundChannel objects */
186
187/* Check for a SndCommand argument */
188static int
189GetSndCommand(PyObject *v, SndCommand *pc)
190{
191 int len;
192 pc->param1 = 0;
193 pc->param2 = 0;
194 if (PyArg_Parse(v, "h", &pc->cmd))
195 return 1;
196 PyErr_Clear();
197 if (PyArg_Parse(v, "(h)", &pc->cmd))
198 return 1;
199 PyErr_Clear();
200 if (PyArg_Parse(v, "(hh)", &pc->cmd, &pc->param1))
201 return 1;
202 PyErr_Clear();
203 if (PyArg_Parse(v, "(hhl)",
204 &pc->cmd, &pc->param1, &pc->param2))
205 return 1;
206 PyErr_Clear();
207 if (PyArg_Parse(v, "(hhs#);SndCommand arg must be 1-3 ints or 2 ints + string",
208 &pc->cmd, &pc->param1, &pc->param2, &len))
209 return 1;
210 return 0;
211}
212
213typedef struct {
214 OB_HEAD
215 SndChannelPtr chan;
216} SndChObject;
217
218staticforward PyTypeObject SndChType;
219
220#define SndChObject_Check(s) ((s)->ob_type == &SndChType)
221
222static SndChObject *
223SndCh_FromSndChannelPtr(SndChannelPtr chan)
224{
225 SndChObject *s = PyObject_NEW(SndChObject, &SndChType);
226 if (s != NULL)
227 s->chan = chan;
228 return s;
229}
230
231static void
232SndCh_Dealloc(SndChObject *s)
233{
234 if (s->chan != NULL) {
235 SndDisposeChannel(s->chan, 1);
Guido van Rossumdf1c4ee1994-09-16 12:48:59 +0000236 if (s->chan->userInfo != 0)
237 DEL((void *)s->chan->userInfo);
Guido van Rossum2d167031994-09-16 10:54:21 +0000238 s->chan = NULL;
239 }
240 PyMem_DEL(s);
241}
242
243static PyObject *
244SndCh_Close(SndChObject *s, PyObject *args)
245{
246 int quietNow = 1;
247 if (args != NULL) {
248 if (!PyArg_Parse(args, "i", &quietNow))
249 return NULL;
250 }
251 if (s->chan != NULL) {
252 SndDisposeChannel(s->chan, quietNow);
Guido van Rossumdf1c4ee1994-09-16 12:48:59 +0000253 if (s->chan->userInfo != 0)
254 DEL((void *)s->chan->userInfo);
Guido van Rossum2d167031994-09-16 10:54:21 +0000255 s->chan = NULL;
256 }
257 Py_INCREF(Py_None);
258 return Py_None;
259}
260
261static PyObject *
262SndCh_SndPlay(SndChObject *s, PyObject *args)
263{
264 RsrcObject *r;
265 int async = 0;
266 if (!PyArg_Parse(args, "(O)", &r)) {
267 PyErr_Clear();
268 if (!PyArg_Parse(args, "(Oi)", &r, &async))
269 return NULL;
270 }
271 if (!RsrcObject_Check(r)) {
272 PyErr_SetString(MacOS_Error,
273 "SndPlay argument must be resource");
274 return NULL;
275 }
276 SndPlay(s->chan, r->h, async);
277 Py_INCREF(Py_None);
278 return Py_None;
279}
280
281static PyObject *
282SndCh_SndDoCommand(SndChObject *s, PyObject *args)
283{
284 SndCommand c;
285 int noWait = 0;
286 OSErr err;
287 if (!PyArg_Parse(args, "(O&)", GetSndCommand, &c)) {
288 PyErr_Clear();
289 if (!PyArg_Parse(args, "(O&i)", GetSndCommand, &c, &noWait))
290 return 0;
291 }
292 err = SndDoCommand(s->chan, &c, noWait);
293 return Err(err);
294}
295
296static PyObject *
297SndCh_SndDoImmediate(SndChObject *s, PyObject *args)
298{
299 SndCommand c;
300 OSErr err;
301 if (!PyArg_Parse(args, "(O&)", GetSndCommand, &c))
302 return 0;
303 err = SndDoImmediate(s->chan, &c);
304 return Err(err);
305}
306
307static PyMethodDef SndCh_Methods[] = {
308 {"close", (PyCFunction)SndCh_Close},
309 {"SndDisposeChannel", (PyCFunction)SndCh_Close},
310 {"SndPlay", (PyCFunction)SndCh_SndPlay, 1},
311 {"SndDoCommand", (PyCFunction)SndCh_SndDoCommand, 1},
312 {"SndDoImmediate", (PyCFunction)SndCh_SndDoImmediate, 1},
313 {NULL, NULL} /* Sentinel */
314};
315
316static PyObject *
317SndCh_GetAttr(PyObject *s, char *name)
318{
319 return Py_FindMethod(SndCh_Methods, s, name);
320}
321
322static PyTypeObject SndChType = {
323 PyObject_HEAD_INIT(&PyType_Type)
324 0,
325 "SoundChannel", /*tp_name*/
326 sizeof(SndChObject), /*tp_basicsize*/
327 0, /*tp_itemsize*/
328 /* methods */
329 (destructor)SndCh_Dealloc, /*tp_dealloc*/
330 0, /*tp_print*/
331 (getattrfunc)SndCh_GetAttr, /*tp_getattr*/
332 0, /*tp_setattr*/
333 0, /*tp_compare*/
334 0, /*tp_repr*/
335 0, /*tp_as_number*/
336 0, /*tp_as_sequence*/
337 0, /*tp_as_mapping*/
338 0, /*tp_hash*/
339};
340
341/*----------------------------------------------------------------------*/
342/* Module */
343
Guido van Rossumdf1c4ee1994-09-16 12:48:59 +0000344typedef struct {
345 long A5;
346 PyObject *callback;
347 PyObject *channel;
348 SndCommand cmd;
349} cbinfo;
350
351static int
352MySafeCallback(arg)
353 void *arg;
354{
355 cbinfo *p = (cbinfo *)arg;
356 PyObject *args;
357 PyObject *res;
358 args = Py_BuildValue("(O(hhl))",
359 p->channel,
360 p->cmd.cmd, p->cmd.param1, p->cmd.param2);
361 res = PyEval_CallObject(p->callback, args);
362 Py_DECREF(args);
363 if (res == NULL)
364 return -1;
365 DECREF(res);
366 return 0;
367}
368
369static pascal void
370MyUserRoutine(SndChannelPtr chan, SndCommand cmd)
371{
372 cbinfo *p = (cbinfo *)chan->userInfo;
373 long A5 = SetA5(p->A5);
374 p->cmd = cmd;
375 Py_AddPendingCall(MySafeCallback, (void *)p);
376 SetA5(A5);
377}
378
Guido van Rossum2d167031994-09-16 10:54:21 +0000379static PyObject *
380MacOS_SndNewChannel(PyObject *self, PyObject *args)
381{
382 SndChannelPtr chan;
383 short synth;
384 long init = 0;
Guido van Rossumdf1c4ee1994-09-16 12:48:59 +0000385 PyObject *callback = NULL;
386 cbinfo *p = NULL;
387 SndCallBackProcPtr userroutine = 0;
Guido van Rossum2d167031994-09-16 10:54:21 +0000388 OSErr err;
Guido van Rossumdf1c4ee1994-09-16 12:48:59 +0000389 PyObject *res;
Guido van Rossum2d167031994-09-16 10:54:21 +0000390 if (!PyArg_Parse(args, "(h)", &synth)) {
391 PyErr_Clear();
Guido van Rossumdf1c4ee1994-09-16 12:48:59 +0000392 if (!PyArg_Parse(args, "(hl)", &synth, &init)) {
393 PyErr_Clear();
394 if (!PyArg_Parse(args, "(hlO)",
395 &synth, &init, &callback))
396 return NULL;
397 }
398 }
399 if (callback != NULL) {
400 p = NEW(cbinfo, 1);
401 if (p == NULL)
402 return PyErr_NoMemory();
403 p->A5 = SetCurrentA5();
404 p->callback = callback;
405 userroutine = MyUserRoutine;
Guido van Rossum2d167031994-09-16 10:54:21 +0000406 }
407 chan = NULL;
Guido van Rossumdf1c4ee1994-09-16 12:48:59 +0000408 err = SndNewChannel(&chan, synth, init, userroutine);
409 if (err) {
410 if (p)
411 DEL(p);
Guido van Rossum2d167031994-09-16 10:54:21 +0000412 return Err(err);
Guido van Rossumdf1c4ee1994-09-16 12:48:59 +0000413 }
414 chan->userInfo = (long)p;
415 res = (PyObject *)SndCh_FromSndChannelPtr(chan);
416 if (res == NULL) {
417 SndDisposeChannel(chan, 1);
418 DEL(p);
419 }
420 else
421 p->channel = res;
422 return res;
Guido van Rossum2d167031994-09-16 10:54:21 +0000423}
424
425static PyObject *
426MacOS_SndPlay(PyObject *self, PyObject *args)
427{
428 RsrcObject *r;
429 OSErr err;
430 if (!PyArg_Parse(args, "(O!)", &RsrcType, &r))
431 return NULL;
432 err = SndPlay((SndChannelPtr)NULL, r->h, 0);
433 return Err(err);
434}
435
436static PyObject *
437MacOS_SndControl(PyObject *self, PyObject *args)
438{
439 int id;
440 SndCommand c;
441 OSErr err;
442 if (!PyArg_Parse(args, "(iO&)", &id, GetSndCommand, &c))
443 return NULL;
444 err = SndControl(id, &c);
445 if (err)
446 return Err(err);
447 return Py_BuildValue("(hhl)", c.cmd, c.param1, c.param2);
448}
449
450static PyMethodDef MacOS_Methods[] = {
451 {"GetResource", MacOS_GetResource, 1},
452 {"GetNamedResource", MacOS_GetNamedResource, 1},
453 {"SndNewChannel", MacOS_SndNewChannel, 1},
454 {"SndPlay", MacOS_SndPlay, 1},
455 {"SndControl", MacOS_SndControl, 1},
456 {NULL, NULL} /* Sentinel */
457};
458
459
460void
461MacOS_Init()
462{
463 PyObject *m, *d;
464
465 m = Py_InitModule("MacOS", MacOS_Methods);
466 d = PyModule_GetDict(m);
467
468 /* Initialize MacOS.Error exception */
469 MacOS_Error = PyString_FromString("MacOS.Error");
Guido van Rossumdf1c4ee1994-09-16 12:48:59 +0000470 if (MacOS_Error == NULL ||
471 PyDict_SetItemString(d, "Error", MacOS_Error) != 0)
Guido van Rossum2d167031994-09-16 10:54:21 +0000472 Py_FatalError("can't define MacOS.Error");
473}