]> git.0d.be Git - jack_mixer.git/blob - jack_mixer_c.c
Rewrote Python binding to jack_mixer.c
[jack_mixer.git] / jack_mixer_c.c
1 #include <Python.h>
2
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdbool.h>
6
7 #include <structmember.h>
8
9 #include "jack_mixer.h"
10
11
12 /** Scale Type **/
13
14 typedef struct {
15         PyObject_HEAD
16         jack_mixer_scale_t scale;
17 } ScaleObject;
18
19 static void
20 Scale_dealloc(ScaleObject *self)
21 {
22         if (self->scale)
23                 scale_destroy(self->scale);
24         self->ob_type->tp_free((PyObject*)self);
25 }
26
27 static int
28 Scale_init(ScaleObject *self, PyObject *args, PyObject *kwds)
29 {
30         self->scale = scale_create();
31         return 0;
32 }
33
34 static PyObject*
35 Scale_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
36 {
37         ScaleObject *self;
38
39         self = (ScaleObject*)type->tp_alloc(type, 0);
40
41         return (PyObject*)self;
42 }
43
44 static PyObject*
45 Scale_add_threshold(ScaleObject *self, PyObject *args)
46 {
47         float db, scale_value;
48
49         if (! PyArg_ParseTuple(args, "ff", &db, &scale_value)) return NULL;
50
51         scale_add_threshold(self->scale, db, scale_value);
52
53         Py_INCREF(Py_None);
54         return Py_None;
55 }
56
57 static PyObject*
58 Scale_calculate_coefficients(ScaleObject *self, PyObject *args)
59 {
60         if (! PyArg_ParseTuple(args, "")) return NULL;
61         scale_calculate_coefficients(self->scale);
62         Py_INCREF(Py_None);
63         return Py_None;
64 }
65
66 static PyObject*
67 Scale_db_to_scale(ScaleObject *self, PyObject *args)
68 {
69         double db;
70         if (! PyArg_ParseTuple(args, "d", &db)) return NULL;
71         return PyFloat_FromDouble(scale_db_to_scale(self->scale, db));
72 }
73
74 static PyObject*
75 Scale_scale_to_db(ScaleObject *self, PyObject *args)
76 {
77         double scale_value;
78         if (! PyArg_ParseTuple(args, "d", &scale_value)) return NULL;
79         return PyFloat_FromDouble(scale_scale_to_db(self->scale, scale_value));
80 }
81
82 static PyMethodDef Scale_methods[] = {
83         {"add_threshold", (PyCFunction)Scale_add_threshold, METH_VARARGS, "Add threshold"},
84         {"calculate_coefficients", (PyCFunction)Scale_calculate_coefficients,
85                 METH_VARARGS, "Calculate coefficients"},
86         {"db_to_scale", (PyCFunction)Scale_db_to_scale, METH_VARARGS, "dB to scale"},
87         {"scale_to_db", (PyCFunction)Scale_scale_to_db, METH_VARARGS, "scale to dB"},
88         {NULL}
89 };
90
91 static PyTypeObject ScaleType = {
92         PyObject_HEAD_INIT(NULL)
93         0,       /*ob_size*/
94         "jack_mixer_c.Scale",    /*tp_name*/
95         sizeof(ScaleObject), /*tp_basicsize*/
96         0,       /*tp_itemsize*/
97         (destructor)Scale_dealloc,       /*tp_dealloc*/
98         0,       /*tp_print*/
99         0,       /*tp_getattr*/
100         0,       /*tp_setattr*/
101         0,       /*tp_compare*/
102         0,       /*tp_repr*/
103         0,       /*tp_as_number*/
104         0,       /*tp_as_sequence*/
105         0,       /*tp_as_mapping*/
106         0,       /*tp_hash */
107         0,       /*tp_call*/
108         0,       /*tp_str*/
109         0,       /*tp_getattro*/
110         0,       /*tp_setattro*/
111         0,       /*tp_as_buffer*/
112         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
113         "Scale objects",           /* tp_doc */
114         0,                         /* tp_traverse */
115         0,                         /* tp_clear */
116         0,                         /* tp_richcompare */
117         0,                         /* tp_weaklistoffset */
118         0,                         /* tp_iter */
119         0,                         /* tp_iternext */
120         Scale_methods,             /* tp_methods */
121         0,             /* tp_members */
122         0,           /* tp_getset */
123         0,                         /* tp_base */
124         0,                         /* tp_dict */
125         0,                         /* tp_descr_get */
126         0,                         /* tp_descr_set */
127         0,                         /* tp_dictoffset */
128         (initproc)Scale_init,      /* tp_init */
129         0,                         /* tp_alloc */
130         Scale_new,                 /* tp_new */
131 };
132
133
134 /** Channel Type **/
135
136 typedef struct {
137         PyObject_HEAD
138         PyObject *midi_change_callback;
139         jack_mixer_channel_t channel;
140 } ChannelObject;
141
142 static void
143 Channel_dealloc(ChannelObject *self)
144 {
145         Py_XDECREF(self->midi_change_callback);
146         self->ob_type->tp_free((PyObject*)self);
147 }
148
149 static int
150 Channel_init(ChannelObject *self, PyObject *args, PyObject *kwds)
151 {
152         self->midi_change_callback = NULL;
153         return 0;
154 }
155
156 static PyObject*
157 Channel_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
158 {
159         ChannelObject *self;
160
161         self = (ChannelObject*)type->tp_alloc(type, 0);
162
163         if (self != NULL) {
164                 self->channel = NULL;
165                 self->midi_change_callback = NULL;
166         }
167
168         return (PyObject*)self;
169 }
170
171 static PyObject*
172 Channel_get_is_stereo(ChannelObject *self, void *closure)
173 {
174         PyObject *result;
175
176         bool is_stereo = channel_is_stereo(self->channel);
177         if (is_stereo) {
178                 result = Py_True;
179         } else {
180                 result = Py_False;
181         }
182         Py_INCREF(result);
183         return result;
184 }
185
186 static PyObject*
187 Channel_get_volume(ChannelObject *self, void *closure)
188 {
189         return PyFloat_FromDouble(channel_volume_read(self->channel));
190 }
191
192 static int
193 Channel_set_volume(ChannelObject *self, PyObject *value, void *closure)
194 {
195         channel_volume_write(self->channel, PyFloat_AsDouble(value));
196         return 0;
197 }
198
199 static PyObject*
200 Channel_get_balance(ChannelObject *self, void *closure)
201 {
202         return PyFloat_FromDouble(channel_balance_read(self->channel));
203 }
204
205 static int
206 Channel_set_balance(ChannelObject *self, PyObject *value, void *closure)
207 {
208         channel_balance_write(self->channel, PyFloat_AsDouble(value));
209         return 0;
210 }
211
212 static PyObject*
213 Channel_get_mute(ChannelObject *self, void *closure)
214 {
215         PyObject *result;
216
217         if (channel_is_muted(self->channel)) {
218                 result = Py_True;
219         } else {
220                 result = Py_False;
221         }
222         Py_INCREF(result);
223         return result;
224 }
225
226 static int
227 Channel_set_mute(ChannelObject *self, PyObject *value, void *closure)
228 {
229         if (value == Py_True) {
230                 channel_mute(self->channel);
231         } else {
232                 channel_unmute(self->channel);
233         }
234         return 0;
235 }
236
237 static PyObject*
238 Channel_get_solo(ChannelObject *self, void *closure)
239 {
240         PyObject *result;
241
242         if (channel_is_soloed(self->channel)) {
243                 result = Py_True;
244         } else {
245                 result = Py_False;
246         }
247         Py_INCREF(result);
248         return result;
249 }
250
251 static int
252 Channel_set_solo(ChannelObject *self, PyObject *value, void *closure)
253 {
254         if (value == Py_True) {
255                 channel_solo(self->channel);
256         } else {
257                 channel_unsolo(self->channel);
258         }
259         return 0;
260 }
261
262 static PyObject*
263 Channel_get_meter(ChannelObject *self, void *closure)
264 {
265         PyObject *result;
266         double left, right;
267
268         if (channel_is_stereo(self->channel)) {
269                 result = PyTuple_New(2);
270                 channel_stereo_meter_read(self->channel, &left, &right);
271                 PyTuple_SetItem(result, 0, PyFloat_FromDouble(left));
272                 PyTuple_SetItem(result, 1, PyFloat_FromDouble(right));
273         } else {
274                 result = PyTuple_New(1);
275                 channel_mono_meter_read(self->channel, &left);
276                 PyTuple_SetItem(result, 0, PyFloat_FromDouble(left));
277         }
278         return result;
279 }
280
281 static PyObject*
282 Channel_get_abspeak(ChannelObject *self, void *closure)
283 {
284         return PyFloat_FromDouble(channel_abspeak_read(self->channel));
285 }
286
287 static int
288 Channel_set_abspeak(ChannelObject *self, PyObject *value, void *closure)
289 {
290         if (value != Py_None) {
291                 fprintf(stderr, "abspeak can only be reset (set to None)\n");
292                 return -1;
293         }
294         channel_abspeak_reset(self->channel);
295         return 0;
296 }
297
298 static int
299 Channel_set_midi_scale(ChannelObject *self, PyObject *value, void *closure)
300 {
301         ScaleObject *scale_object = (ScaleObject*)value; /* XXX: check */
302
303         channel_set_midi_scale(self->channel, scale_object->scale);
304         return 0;
305 }
306
307
308 static PyObject*
309 Channel_get_midi_change_callback(ChannelObject *self, void *closure)
310 {
311         if (self->midi_change_callback) {
312                 Py_INCREF(self->midi_change_callback);
313                 return self->midi_change_callback;
314         } else {
315                 Py_INCREF(Py_None);
316                 return Py_None;
317         }
318 }
319
320 static void
321 channel_midi_callback(void *userdata)
322 {
323         ChannelObject *self = (ChannelObject*)userdata;
324         PyGILState_STATE gstate;
325
326         gstate = PyGILState_Ensure();
327         PyObject_CallObject(self->midi_change_callback, NULL);
328         PyGILState_Release(gstate);
329 }
330
331 static int
332 Channel_set_midi_change_callback(ChannelObject *self, PyObject *value, void *closure)
333 {
334         if (value == Py_None) {
335                 self->midi_change_callback = NULL;
336                 channel_set_midi_change_callback(self->channel, NULL, NULL);
337         } else {
338                 if (!PyCallable_Check(value)) {
339                         PyErr_SetString(PyExc_TypeError, "value must be callable");
340                         return -1;
341                 }
342                 if (self->midi_change_callback) {
343                         Py_XDECREF(self->midi_change_callback);
344                 }
345                 Py_INCREF(value);
346                 self->midi_change_callback = value;
347                 channel_set_midi_change_callback(self->channel,
348                                 channel_midi_callback, self);
349         }
350
351         return 0;
352 }
353
354 static PyObject*
355 Channel_get_name(ChannelObject *self, void *closure)
356 {
357         return PyString_FromString(channel_get_name(self->channel));
358 }
359
360 static int
361 Channel_set_name(ChannelObject *self, PyObject *value, void *closure)
362 {
363         channel_rename(self->channel, PyString_AsString(value));
364         return 0;
365 }
366
367
368 static PyGetSetDef Channel_getseters[] = {
369         {"is_stereo", 
370                 (getter)Channel_get_is_stereo, NULL,
371                 "mono/stereo", NULL},
372         {"volume", 
373                 (getter)Channel_get_volume, (setter)Channel_set_volume,
374                 "volume", NULL},
375         {"balance", 
376                 (getter)Channel_get_balance, (setter)Channel_set_balance,
377                 "balance", NULL},
378         {"mute", 
379                 (getter)Channel_get_mute, (setter)Channel_set_mute,
380                 "mute", NULL},
381         {"solo", 
382                 (getter)Channel_get_solo, (setter)Channel_set_solo,
383                 "solo", NULL},
384         {"meter",
385                 (getter)Channel_get_meter, NULL,
386                 "meter", NULL},
387         {"abspeak", 
388                 (getter)Channel_get_abspeak, (setter)Channel_set_abspeak,
389                 "balance", NULL},
390         {"midi_scale",
391                 NULL, (setter)Channel_set_midi_scale,
392                 "midi scale", NULL},
393         {"midi_change_callback",
394                 (getter)Channel_get_midi_change_callback,
395                 (setter)Channel_set_midi_change_callback,
396                 "midi change callback", NULL},
397         {"name",
398                 (getter)Channel_get_name,
399                 (setter)Channel_set_name,
400                 "name", NULL},
401         {NULL}
402 };
403
404 static PyObject*
405 Channel_remove(ChannelObject *self, PyObject *args)
406 {
407         if (! PyArg_ParseTuple(args, "")) return NULL;
408         remove_channel(self->channel);
409         Py_INCREF(Py_None);
410         return Py_None;
411 }
412
413
414 static PyMethodDef channel_methods[] = {
415         {"remove", (PyCFunction)Channel_remove, METH_VARARGS, "Remove"},
416         {NULL}
417 };
418
419 static PyTypeObject ChannelType = {
420         PyObject_HEAD_INIT(NULL)
421         0,       /*ob_size*/
422         "jack_mixer_c.Channel",    /*tp_name*/
423         sizeof(ChannelObject), /*tp_basicsize*/
424         0,       /*tp_itemsize*/
425         (destructor)Channel_dealloc,       /*tp_dealloc*/
426         0,       /*tp_print*/
427         0,       /*tp_getattr*/
428         0,       /*tp_setattr*/
429         0,       /*tp_compare*/
430         0,       /*tp_repr*/
431         0,       /*tp_as_number*/
432         0,       /*tp_as_sequence*/
433         0,       /*tp_as_mapping*/
434         0,       /*tp_hash */
435         0,       /*tp_call*/
436         0,       /*tp_str*/
437         0,       /*tp_getattro*/
438         0,       /*tp_setattro*/
439         0,       /*tp_as_buffer*/
440         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
441         "Channel objects",           /* tp_doc */
442         0,                         /* tp_traverse */
443         0,                         /* tp_clear */
444         0,                         /* tp_richcompare */
445         0,                         /* tp_weaklistoffset */
446         0,                         /* tp_iter */
447         0,                         /* tp_iternext */
448         channel_methods,           /* tp_methods */
449         0,             /* tp_members */
450         Channel_getseters,           /* tp_getset */
451         0,                         /* tp_base */
452         0,                         /* tp_dict */
453         0,                         /* tp_descr_get */
454         0,                         /* tp_descr_set */
455         0,                         /* tp_dictoffset */
456         (initproc)Channel_init,    /* tp_init */
457         0,                         /* tp_alloc */
458         Channel_new,                 /* tp_new */
459 };
460
461 static PyObject*
462 Channel_New(jack_mixer_channel_t channel)
463 {
464         ChannelObject *self;
465         self = (ChannelObject*)PyObject_NEW(ChannelObject, &ChannelType);
466         if (self != NULL) {
467                 self->channel = channel;
468                 self->midi_change_callback = NULL;
469         }
470         return (PyObject*)self;
471 }
472
473 /** Mixer Type **/
474
475 typedef struct {
476         PyObject_HEAD
477         PyObject *main_mix_channel;
478         jack_mixer_t mixer;
479 } MixerObject;
480
481 static void
482 Mixer_dealloc(MixerObject *self)
483 {
484         Py_XDECREF(self->main_mix_channel);
485         if (self->mixer)
486                 destroy(self->mixer);
487         self->ob_type->tp_free((PyObject*)self);
488 }
489
490 static PyObject*
491 Mixer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
492 {
493         MixerObject *self;
494
495         self = (MixerObject*)type->tp_alloc(type, 0);
496
497         if (self != NULL) {
498                 self->main_mix_channel = NULL;
499                 self->mixer = NULL;
500         }
501
502         return (PyObject*)self;
503 }
504
505 static int
506 Mixer_init(MixerObject *self, PyObject *args, PyObject *kwds)
507 {
508         static char *kwlist[] = {"name", NULL};
509         char *name;
510
511         if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &name))
512                 return -1;
513         
514         self->mixer = create(name);
515         if (self->mixer == NULL) {
516                 return -1;
517         }
518
519         self->main_mix_channel = Channel_New(get_main_mix_channel(self->mixer));
520
521         return 0;
522 }
523
524 static PyMemberDef Mixer_members[] = {
525         {"main_mix_channel", T_OBJECT, offsetof(MixerObject, main_mix_channel), 0, "main_mix_channel"},
526         {NULL}
527 };
528
529 static PyObject*
530 Mixer_get_channels_count(MixerObject *self, void *closure)
531 {
532         return PyInt_FromLong(get_channels_count(self->mixer));
533 }
534
535 static PyGetSetDef Mixer_getseters[] = {
536         {"channels_count", (getter)Mixer_get_channels_count, NULL,
537                 "channels count", NULL},
538         {NULL}
539 };
540
541 static PyObject*
542 Mixer_add_channel(MixerObject *self, PyObject *args)
543 {
544         char *name;
545         int stereo;
546         jack_mixer_channel_t channel;
547
548         if (! PyArg_ParseTuple(args, "sb", &name, &stereo)) return NULL;
549
550         channel = add_channel(self->mixer, name, (bool)stereo);
551
552         return Channel_New(channel);
553 }
554
555 static PyMethodDef Mixer_methods[] = {
556         {"add_channel", (PyCFunction)Mixer_add_channel, METH_VARARGS, "Add a new channel"},
557 //      {"remove_channel", (PyCFunction)Mixer_remove_channel, METH_VARARGS, "Remove a channel"},
558         {NULL}
559 };
560
561 static PyTypeObject MixerType = {
562         PyObject_HEAD_INIT(NULL)
563         0,       /*ob_size*/
564         "jack_mixer_c.Mixer",    /*tp_name*/
565         sizeof(MixerObject), /*tp_basicsize*/
566         0,       /*tp_itemsize*/
567         (destructor)Mixer_dealloc,       /*tp_dealloc*/
568         0,       /*tp_print*/
569         0,       /*tp_getattr*/
570         0,       /*tp_setattr*/
571         0,       /*tp_compare*/
572         0,       /*tp_repr*/
573         0,       /*tp_as_number*/
574         0,       /*tp_as_sequence*/
575         0,       /*tp_as_mapping*/
576         0,       /*tp_hash */
577         0,       /*tp_call*/
578         0,       /*tp_str*/
579         0,       /*tp_getattro*/
580         0,       /*tp_setattro*/
581         0,       /*tp_as_buffer*/
582         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
583         "Mixer objects",           /* tp_doc */
584         0,                         /* tp_traverse */
585         0,                         /* tp_clear */
586         0,                         /* tp_richcompare */
587         0,                         /* tp_weaklistoffset */
588         0,                         /* tp_iter */
589         0,                         /* tp_iternext */
590         Mixer_methods,             /* tp_methods */
591         Mixer_members,             /* tp_members */
592         Mixer_getseters,           /* tp_getset */
593         0,                         /* tp_base */
594         0,                         /* tp_dict */
595         0,                         /* tp_descr_get */
596         0,                         /* tp_descr_set */
597         0,                         /* tp_dictoffset */
598         (initproc)Mixer_init,      /* tp_init */
599         0,                         /* tp_alloc */
600         Mixer_new,                 /* tp_new */
601 };
602
603
604 static PyMethodDef jack_mixer_methods[] = {
605         {NULL}  /* Sentinel */
606 };
607
608
609
610 PyMODINIT_FUNC initjack_mixer_c(void)
611 {
612         PyObject *m;
613
614         if (PyType_Ready(&MixerType) < 0)
615                 return;
616         if (PyType_Ready(&ChannelType) < 0)
617                 return;
618         if (PyType_Ready(&ScaleType) < 0)
619                 return;
620         
621         m = Py_InitModule3("jack_mixer_c", jack_mixer_methods, "Jack Mixer C Helper Module");
622
623         Py_INCREF(&MixerType);
624         PyModule_AddObject(m, "Mixer", (PyObject*)&MixerType);
625         Py_INCREF(&ChannelType);
626         PyModule_AddObject(m, "Channel", (PyObject*)&ChannelType);
627         Py_INCREF(&ScaleType);
628         PyModule_AddObject(m, "Scale", (PyObject*)&ScaleType);
629 }
630