Maintain object property encapsulation
[jack_mixer.git] / jack_mixer_c.c
blobecddefce0c422a1511e7ae6caae310fdc2e7d5cb
1 /*
2 * This file is part of jack_mixer
4 * Copyright (C) 2009 Frederic Peters <fpeters@0d.be>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include <Python.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdbool.h>
26 #include <structmember.h>
28 #include "jack_mixer.h"
31 /** Scale Type **/
33 typedef struct {
34 PyObject_HEAD
35 jack_mixer_scale_t scale;
36 } ScaleObject;
38 static void
39 Scale_dealloc(ScaleObject *self)
41 if (self->scale)
42 scale_destroy(self->scale);
43 Py_TYPE(self)->tp_free((PyObject*)self);
46 static int
47 Scale_init(ScaleObject *self, PyObject *args, PyObject *kwds)
49 self->scale = scale_create();
50 return 0;
53 static PyObject*
54 Scale_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
56 ScaleObject *self;
58 self = (ScaleObject*)type->tp_alloc(type, 0);
60 return (PyObject*)self;
63 static PyObject*
64 Scale_add_threshold(ScaleObject *self, PyObject *args)
66 float db, scale_value;
68 if (! PyArg_ParseTuple(args, "ff", &db, &scale_value)) return NULL;
70 scale_add_threshold(self->scale, db, scale_value);
72 Py_INCREF(Py_None);
73 return Py_None;
76 static PyObject*
77 Scale_calculate_coefficients(ScaleObject *self, PyObject *args)
79 if (! PyArg_ParseTuple(args, "")) return NULL;
80 scale_calculate_coefficients(self->scale);
81 Py_INCREF(Py_None);
82 return Py_None;
85 static PyObject*
86 Scale_db_to_scale(ScaleObject *self, PyObject *args)
88 double db;
89 if (! PyArg_ParseTuple(args, "d", &db)) return NULL;
90 return PyFloat_FromDouble(scale_db_to_scale(self->scale, db));
93 static PyObject*
94 Scale_scale_to_db(ScaleObject *self, PyObject *args)
96 double scale_value;
97 if (! PyArg_ParseTuple(args, "d", &scale_value)) return NULL;
98 return PyFloat_FromDouble(scale_scale_to_db(self->scale, scale_value));
101 static PyMethodDef Scale_methods[] = {
102 {"add_threshold", (PyCFunction)Scale_add_threshold, METH_VARARGS, "Add threshold"},
103 {"calculate_coefficients", (PyCFunction)Scale_calculate_coefficients,
104 METH_VARARGS, "Calculate coefficients"},
105 {"db_to_scale", (PyCFunction)Scale_db_to_scale, METH_VARARGS, "dB to scale"},
106 {"scale_to_db", (PyCFunction)Scale_scale_to_db, METH_VARARGS, "scale to dB"},
107 {NULL}
110 static PyTypeObject ScaleType = {
111 PyVarObject_HEAD_INIT(NULL, 0)
112 "jack_mixer_c.Scale", /*tp_name*/
113 sizeof(ScaleObject), /*tp_basicsize*/
114 0, /*tp_itemsize*/
115 (destructor)Scale_dealloc, /*tp_dealloc*/
116 0, /*tp_print*/
117 0, /*tp_getattr*/
118 0, /*tp_setattr*/
119 0, /*tp_compare*/
120 0, /*tp_repr*/
121 0, /*tp_as_number*/
122 0, /*tp_as_sequence*/
123 0, /*tp_as_mapping*/
124 0, /*tp_hash */
125 0, /*tp_call*/
126 0, /*tp_str*/
127 0, /*tp_getattro*/
128 0, /*tp_setattro*/
129 0, /*tp_as_buffer*/
130 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
131 "Scale objects", /* tp_doc */
132 0, /* tp_traverse */
133 0, /* tp_clear */
134 0, /* tp_richcompare */
135 0, /* tp_weaklistoffset */
136 0, /* tp_iter */
137 0, /* tp_iternext */
138 Scale_methods, /* tp_methods */
139 0, /* tp_members */
140 0, /* tp_getset */
141 0, /* tp_base */
142 0, /* tp_dict */
143 0, /* tp_descr_get */
144 0, /* tp_descr_set */
145 0, /* tp_dictoffset */
146 (initproc)Scale_init, /* tp_init */
147 0, /* tp_alloc */
148 Scale_new, /* tp_new */
152 /** Channel Type **/
154 typedef struct {
155 PyObject_HEAD
156 PyObject *midi_change_callback;
157 jack_mixer_channel_t channel;
158 } ChannelObject;
160 static void
161 Channel_dealloc(ChannelObject *self)
163 Py_XDECREF(self->midi_change_callback);
164 Py_TYPE(self)->tp_free((PyObject*)self);
167 static int
168 Channel_init(ChannelObject *self, PyObject *args, PyObject *kwds)
170 self->midi_change_callback = NULL;
171 return 0;
174 static PyObject*
175 Channel_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
177 ChannelObject *self;
179 self = (ChannelObject*)type->tp_alloc(type, 0);
181 if (self != NULL) {
182 self->channel = NULL;
183 self->midi_change_callback = NULL;
186 return (PyObject*)self;
189 static PyObject*
190 Channel_get_is_stereo(ChannelObject *self, void *closure)
192 PyObject *result;
194 bool is_stereo = channel_is_stereo(self->channel);
195 if (is_stereo) {
196 result = Py_True;
197 } else {
198 result = Py_False;
200 Py_INCREF(result);
201 return result;
204 static PyObject*
205 Channel_get_volume(ChannelObject *self, void *closure)
207 return PyFloat_FromDouble(channel_volume_read(self->channel));
210 static int
211 Channel_set_volume(ChannelObject *self, PyObject *value, void *closure)
213 if (self->channel == NULL) {
214 PyErr_SetString(PyExc_RuntimeError, "unitialized channel");
215 return -1;
217 channel_volume_write(self->channel, PyFloat_AsDouble(value));
218 channel_set_midi_cc_volume_picked_up(self->channel, false);
219 return 0;
222 static PyObject*
223 Channel_get_balance(ChannelObject *self, void *closure)
225 return PyFloat_FromDouble(channel_balance_read(self->channel));
228 static int
229 Channel_set_balance(ChannelObject *self, PyObject *value, void *closure)
231 channel_balance_write(self->channel, PyFloat_AsDouble(value));
232 channel_set_midi_cc_balance_picked_up(self->channel, false);
233 return 0;
236 static PyObject*
237 Channel_get_out_mute(ChannelObject *self, void *closure)
239 PyObject *result;
241 if (channel_is_out_muted(self->channel)) {
242 result = Py_True;
243 } else {
244 result = Py_False;
246 Py_INCREF(result);
247 return result;
250 static int
251 Channel_set_out_mute(ChannelObject *self, PyObject *value, void *closure)
253 if (value == Py_True) {
254 channel_out_mute(self->channel);
255 } else {
256 channel_out_unmute(self->channel);
258 return 0;
261 static PyObject*
262 Channel_get_solo(ChannelObject *self, void *closure)
264 PyObject *result;
266 if (channel_is_soloed(self->channel)) {
267 result = Py_True;
268 } else {
269 result = Py_False;
271 Py_INCREF(result);
272 return result;
275 static int
276 Channel_set_solo(ChannelObject *self, PyObject *value, void *closure)
278 if (value == Py_True) {
279 channel_solo(self->channel);
280 } else {
281 channel_unsolo(self->channel);
283 return 0;
286 static PyObject*
287 Channel_get_meter(ChannelObject *self, void *closure)
289 PyObject *result;
290 double left, right;
292 if (channel_is_stereo(self->channel)) {
293 result = PyTuple_New(2);
294 channel_stereo_meter_read(self->channel, &left, &right);
295 PyTuple_SetItem(result, 0, PyFloat_FromDouble(left));
296 PyTuple_SetItem(result, 1, PyFloat_FromDouble(right));
297 } else {
298 result = PyTuple_New(1);
299 channel_mono_meter_read(self->channel, &left);
300 PyTuple_SetItem(result, 0, PyFloat_FromDouble(left));
302 return result;
305 static PyObject*
306 Channel_get_kmeter(ChannelObject *self, void *closure)
308 PyObject *result;
309 double peak_left, peak_right, rms_left, rms_right;
311 if (channel_is_stereo(self->channel)) {
312 result = PyTuple_New(4);
313 channel_stereo_kmeter_read(self->channel, &peak_left, &peak_right, &rms_left, &rms_right);
314 PyTuple_SetItem(result, 0, PyFloat_FromDouble(peak_left));
315 PyTuple_SetItem(result, 1, PyFloat_FromDouble(peak_right));
316 PyTuple_SetItem(result, 2, PyFloat_FromDouble(rms_left));
317 PyTuple_SetItem(result, 3, PyFloat_FromDouble(rms_right));
318 } else {
319 result = PyTuple_New(2);
320 channel_mono_kmeter_read(self->channel, &peak_left, &rms_left);
321 PyTuple_SetItem(result, 0, PyFloat_FromDouble(peak_left));
322 PyTuple_SetItem(result, 1, PyFloat_FromDouble(rms_left));
324 return result;
327 static PyObject*
328 Channel_get_abspeak(ChannelObject *self, void *closure)
330 return PyFloat_FromDouble(channel_abspeak_read(self->channel));
333 static int
334 Channel_set_abspeak(ChannelObject *self, PyObject *value, void *closure)
336 if (value != Py_None) {
337 fprintf(stderr, "abspeak can only be reset (set to None)\n");
338 return -1;
340 channel_abspeak_reset(self->channel);
341 return 0;
344 static int
345 Channel_set_midi_scale(ChannelObject *self, PyObject *value, void *closure)
347 ScaleObject *scale_object = (ScaleObject*)value; /* XXX: check */
349 channel_set_midi_scale(self->channel, scale_object->scale);
350 return 0;
354 static PyObject*
355 Channel_get_midi_change_callback(ChannelObject *self, void *closure)
357 if (self->midi_change_callback) {
358 Py_INCREF(self->midi_change_callback);
359 return self->midi_change_callback;
360 } else {
361 Py_INCREF(Py_None);
362 return Py_None;
366 static void
367 channel_midi_callback(void *userdata)
369 ChannelObject *self = (ChannelObject*)userdata;
370 PyGILState_STATE gstate;
372 gstate = PyGILState_Ensure();
373 PyObject_CallObject(self->midi_change_callback, NULL);
374 PyGILState_Release(gstate);
377 static int
378 Channel_set_midi_change_callback(ChannelObject *self, PyObject *value, void *closure)
380 if (value == Py_None) {
381 self->midi_change_callback = NULL;
382 channel_set_midi_change_callback(self->channel, NULL, NULL);
383 } else {
384 if (!PyCallable_Check(value)) {
385 PyErr_SetString(PyExc_TypeError, "value must be callable");
386 return -1;
388 if (self->midi_change_callback) {
389 Py_XDECREF(self->midi_change_callback);
391 Py_INCREF(value);
392 self->midi_change_callback = value;
393 channel_set_midi_change_callback(self->channel,
394 channel_midi_callback, self);
397 return 0;
400 static PyObject*
401 Channel_get_name(ChannelObject *self, void *closure)
403 return PyUnicode_FromString(channel_get_name(self->channel));
406 static int
407 Channel_set_name(ChannelObject *self, PyObject *value, void *closure)
409 channel_rename(self->channel, PyUnicode_AsUTF8(value));
410 return 0;
413 static PyObject*
414 Channel_get_balance_midi_cc(ChannelObject *self, void *closure)
416 return PyLong_FromLong(channel_get_balance_midi_cc(self->channel));
419 static int
420 Channel_set_balance_midi_cc(ChannelObject *self, PyObject *value, void *closure)
422 int new_cc;
423 unsigned int result;
425 new_cc = PyLong_AsLong(value);
426 result = channel_set_balance_midi_cc(self->channel, (int8_t)new_cc);
427 if (result == 0) {
428 return 0;
430 if (result == 2) {
431 PyErr_SetString(PyExc_RuntimeError, "value out of range");
433 return -1;
436 static PyObject*
437 Channel_get_volume_midi_cc(ChannelObject *self, void *closure)
439 return PyLong_FromLong(channel_get_volume_midi_cc(self->channel));
442 static int
443 Channel_set_volume_midi_cc(ChannelObject *self, PyObject *value, void *closure)
445 int new_cc;
446 unsigned int result;
448 new_cc = PyLong_AsLong(value);
449 result = channel_set_volume_midi_cc(self->channel, (int8_t)new_cc);
450 if (result == 0) {
451 return 0;
453 if (result == 2) {
454 PyErr_SetString(PyExc_RuntimeError, "value out of range");
456 return -1;
459 static PyObject*
460 Channel_get_mute_midi_cc(ChannelObject *self, void *closure)
462 return PyLong_FromLong(channel_get_mute_midi_cc(self->channel));
465 static int
466 Channel_set_mute_midi_cc(ChannelObject *self, PyObject *value, void *closure)
468 int new_cc;
469 unsigned int result;
471 new_cc = PyLong_AsLong(value);
472 result = channel_set_mute_midi_cc(self->channel, (int8_t)new_cc);
473 if (result == 0) {
474 return 0;
476 if (result == 2) {
477 PyErr_SetString(PyExc_RuntimeError, "value out of range");
479 return -1;
482 static PyObject*
483 Channel_get_solo_midi_cc(ChannelObject *self, void *closure)
485 return PyLong_FromLong(channel_get_solo_midi_cc(self->channel));
488 static int
489 Channel_set_solo_midi_cc(ChannelObject *self, PyObject *value, void *closure)
491 int new_cc;
492 unsigned int result;
494 new_cc = PyLong_AsLong(value);
495 result = channel_set_solo_midi_cc(self->channel, (int8_t)new_cc);
496 if (result == 0) {
497 return 0;
499 if (result == 2) {
500 PyErr_SetString(PyExc_RuntimeError, "value out of range");
502 return -1;
505 static PyObject*
506 Channel_get_midi_in_got_events(ChannelObject *self, void *closure)
508 PyObject *result;
510 if (channel_get_midi_in_got_events(self->channel)) {
511 result = Py_True;
512 } else {
513 result = Py_False;
515 Py_INCREF(result);
516 return result;
519 static PyGetSetDef Channel_getseters[] = {
520 {"is_stereo",
521 (getter)Channel_get_is_stereo, NULL,
522 "mono/stereo", NULL},
523 {"volume",
524 (getter)Channel_get_volume, (setter)Channel_set_volume,
525 "volume", NULL},
526 {"balance",
527 (getter)Channel_get_balance, (setter)Channel_set_balance,
528 "balance", NULL},
529 {"out_mute",
530 (getter)Channel_get_out_mute, (setter)Channel_set_out_mute,
531 "out_mute", NULL},
532 {"solo",
533 (getter)Channel_get_solo, (setter)Channel_set_solo,
534 "solo", NULL},
535 {"meter",
536 (getter)Channel_get_meter, NULL,
537 "meter", NULL},
538 {"kmeter",
539 (getter)Channel_get_kmeter, NULL,
540 "kmeter", NULL},
541 {"abspeak",
542 (getter)Channel_get_abspeak, (setter)Channel_set_abspeak,
543 "balance", NULL},
544 {"midi_scale",
545 NULL, (setter)Channel_set_midi_scale,
546 "midi scale", NULL},
547 {"midi_change_callback",
548 (getter)Channel_get_midi_change_callback,
549 (setter)Channel_set_midi_change_callback,
550 "midi change callback", NULL},
551 {"name",
552 (getter)Channel_get_name,
553 (setter)Channel_set_name,
554 "name", NULL},
555 {"balance_midi_cc",
556 (getter)Channel_get_balance_midi_cc,
557 (setter)Channel_set_balance_midi_cc,
558 "Balance MIDI CC", NULL},
559 {"volume_midi_cc",
560 (getter)Channel_get_volume_midi_cc,
561 (setter)Channel_set_volume_midi_cc,
562 "Volume MIDI CC", NULL},
563 {"mute_midi_cc",
564 (getter)Channel_get_mute_midi_cc,
565 (setter)Channel_set_mute_midi_cc,
566 "Mute MIDI CC", NULL},
567 {"solo_midi_cc",
568 (getter)Channel_get_solo_midi_cc,
569 (setter)Channel_set_solo_midi_cc,
570 "Mute MIDI CC", NULL},
571 {"midi_in_got_events",
572 (getter)Channel_get_midi_in_got_events, NULL,
573 "Got new MIDI IN events", NULL},
574 {NULL}
577 static PyObject*
578 Channel_remove(ChannelObject *self, PyObject *args)
580 if (! PyArg_ParseTuple(args, "")) return NULL;
581 remove_channel(self->channel);
582 Py_INCREF(Py_None);
583 return Py_None;
586 static PyObject*
587 Channel_autoset_volume_midi_cc(ChannelObject *self, PyObject *args)
589 unsigned int result;
590 if (! PyArg_ParseTuple(args, "")) return NULL;
592 result = channel_autoset_volume_midi_cc(self->channel);
594 if (result < 0) {
595 PyErr_SetString(PyExc_RuntimeError, "No free CC for channel volume.");
598 return PyLong_FromLong(result);
601 static PyObject*
602 Channel_autoset_balance_midi_cc(ChannelObject *self, PyObject *args)
604 unsigned int result;
605 if (! PyArg_ParseTuple(args, "")) return NULL;
607 result = channel_autoset_balance_midi_cc(self->channel);
609 if (result < 0) {
610 PyErr_SetString(PyExc_RuntimeError, "No free CC for channel balance.");
613 return PyLong_FromLong(result);
616 static PyObject*
617 Channel_autoset_mute_midi_cc(ChannelObject *self, PyObject *args)
619 unsigned int result;
620 if (! PyArg_ParseTuple(args, "")) return NULL;
622 result = channel_autoset_mute_midi_cc(self->channel);
624 if (result < 0) {
625 PyErr_SetString(PyExc_RuntimeError, "No free CC for channel mute.");
628 return PyLong_FromLong(result);
631 static PyObject*
632 Channel_autoset_solo_midi_cc(ChannelObject *self, PyObject *args)
634 unsigned int result;
635 if (! PyArg_ParseTuple(args, "")) return NULL;
637 result = channel_autoset_solo_midi_cc(self->channel);
639 if (result < 0) {
640 PyErr_SetString(PyExc_RuntimeError, "No free CC channel solo.");
643 return PyLong_FromLong(result);
646 static PyMethodDef channel_methods[] = {
647 {"remove", (PyCFunction)Channel_remove, METH_VARARGS, "Remove"},
648 {"autoset_volume_midi_cc",
649 (PyCFunction)Channel_autoset_volume_midi_cc, METH_VARARGS, "Autoset Volume MIDI CC"},
650 {"autoset_balance_midi_cc",
651 (PyCFunction)Channel_autoset_balance_midi_cc, METH_VARARGS, "Autoset Balance MIDI CC"},
652 {"autoset_mute_midi_cc",
653 (PyCFunction)Channel_autoset_mute_midi_cc, METH_VARARGS, "Autoset Mute MIDI CC"},
654 {"autoset_solo_midi_cc",
655 (PyCFunction)Channel_autoset_solo_midi_cc, METH_VARARGS, "Autoset Solo MIDI CC"},
656 {NULL}
659 static PyTypeObject ChannelType = {
660 PyVarObject_HEAD_INIT(NULL, 0)
661 "jack_mixer_c.Channel", /*tp_name*/
662 sizeof(ChannelObject), /*tp_basicsize*/
663 0, /*tp_itemsize*/
664 (destructor)Channel_dealloc, /*tp_dealloc*/
665 0, /*tp_print*/
666 0, /*tp_getattr*/
667 0, /*tp_setattr*/
668 0, /*tp_compare*/
669 0, /*tp_repr*/
670 0, /*tp_as_number*/
671 0, /*tp_as_sequence*/
672 0, /*tp_as_mapping*/
673 0, /*tp_hash */
674 0, /*tp_call*/
675 0, /*tp_str*/
676 0, /*tp_getattro*/
677 0, /*tp_setattro*/
678 0, /*tp_as_buffer*/
679 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
680 "Channel objects", /* tp_doc */
681 0, /* tp_traverse */
682 0, /* tp_clear */
683 0, /* tp_richcompare */
684 0, /* tp_weaklistoffset */
685 0, /* tp_iter */
686 0, /* tp_iternext */
687 channel_methods, /* tp_methods */
688 0, /* tp_members */
689 Channel_getseters, /* tp_getset */
690 0, /* tp_base */
691 0, /* tp_dict */
692 0, /* tp_descr_get */
693 0, /* tp_descr_set */
694 0, /* tp_dictoffset */
695 (initproc)Channel_init, /* tp_init */
696 0, /* tp_alloc */
697 Channel_new, /* tp_new */
700 static PyObject*
701 Channel_New(jack_mixer_channel_t channel)
703 ChannelObject *self;
704 self = (ChannelObject*)PyObject_NEW(ChannelObject, &ChannelType);
705 if (self != NULL) {
706 self->channel = channel;
707 self->midi_change_callback = NULL;
709 return (PyObject*)self;
712 /** Output Channel Type **/
714 typedef struct {
715 PyObject_HEAD
716 PyObject *midi_change_callback;
717 jack_mixer_output_channel_t *output_channel;
718 } OutputChannelObject;
720 static int
721 OutputChannel_set_prefader(OutputChannelObject *self, PyObject *value, void *closure)
723 if (value == Py_True) {
724 output_channel_set_prefader(self->output_channel, true);
725 } else {
726 output_channel_set_prefader(self->output_channel, false);
728 return 0;
731 static PyObject*
732 OutputChannel_get_prefader(OutputChannelObject *self, void *closure)
734 PyObject *result;
736 if (output_channel_is_prefader(self->output_channel)) {
737 result = Py_True;
738 } else {
739 result = Py_False;
741 Py_INCREF(result);
742 return result;
745 static PyGetSetDef OutputChannel_getseters[] = {
746 {"prefader",
747 (getter)OutputChannel_get_prefader, (setter)OutputChannel_set_prefader,
748 "prefader", NULL},
749 {NULL}
752 static PyObject*
753 OutputChannel_remove(OutputChannelObject *self, PyObject *args)
755 if (! PyArg_ParseTuple(args, "")) return NULL;
756 remove_output_channel(self->output_channel);
757 Py_INCREF(Py_None);
758 return Py_None;
761 static PyObject*
762 OutputChannel_set_solo(OutputChannelObject *self, PyObject *args)
764 PyObject *channel;
765 unsigned char solo;
767 if (! PyArg_ParseTuple(args, "Ob", &channel, &solo)) return NULL;
769 output_channel_set_solo(self->output_channel,
770 ((ChannelObject*)channel)->channel,
771 solo);
773 Py_INCREF(Py_None);
774 return Py_None;
777 static PyObject*
778 OutputChannel_set_muted(OutputChannelObject *self, PyObject *args)
780 PyObject *channel;
781 unsigned char muted;
783 if (! PyArg_ParseTuple(args, "Ob", &channel, &muted)) return NULL;
785 output_channel_set_muted(self->output_channel,
786 ((ChannelObject*)channel)->channel,
787 muted);
789 Py_INCREF(Py_None);
790 return Py_None;
793 static PyObject*
794 OutputChannel_is_solo(OutputChannelObject *self, PyObject *args)
796 PyObject *channel;
797 PyObject *result;
799 if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
801 if (output_channel_is_solo(self->output_channel,
802 ((ChannelObject*)channel)->channel)) {
803 result = Py_True;
804 } else {
805 result = Py_False;
808 Py_INCREF(result);
809 return result;
812 static PyObject*
813 OutputChannel_is_muted(OutputChannelObject *self, PyObject *args)
815 PyObject *channel;
816 PyObject *result;
818 if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
820 if (output_channel_is_muted(self->output_channel,
821 ((ChannelObject*)channel)->channel)) {
822 result = Py_True;
823 } else {
824 result = Py_False;
827 Py_INCREF(result);
828 return result;
831 static PyObject*
832 OutputChannel_set_in_prefader(OutputChannelObject *self, PyObject *args)
834 PyObject *channel;
835 unsigned char prefader;
837 if (! PyArg_ParseTuple(args, "Ob", &channel, &prefader)) return NULL;
839 output_channel_set_in_prefader(self->output_channel,
840 ((ChannelObject*)channel)->channel,
841 prefader);
843 Py_INCREF(Py_None);
844 return Py_None;
847 static PyObject*
848 OutputChannel_is_in_prefader(OutputChannelObject *self, PyObject *args)
850 PyObject *channel;
851 PyObject *result;
853 if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
855 if (output_channel_is_in_prefader(self->output_channel,
856 ((ChannelObject*)channel)->channel)) {
857 result = Py_True;
858 } else {
859 result = Py_False;
862 Py_INCREF(result);
863 return result;
866 static PyMethodDef output_channel_methods[] = {
867 {"remove", (PyCFunction)OutputChannel_remove, METH_VARARGS, "Remove"},
868 {"set_solo", (PyCFunction)OutputChannel_set_solo, METH_VARARGS, "Set a channel as solo"},
869 {"set_muted", (PyCFunction)OutputChannel_set_muted, METH_VARARGS, "Set a channel as muted"},
870 {"is_solo", (PyCFunction)OutputChannel_is_solo, METH_VARARGS, "Is a channel set as solo"},
871 {"is_muted", (PyCFunction)OutputChannel_is_muted, METH_VARARGS, "Is a channel set as muted"},
872 {"set_in_prefader", (PyCFunction)OutputChannel_set_in_prefader, METH_VARARGS, "Set a channel as prefader"},
873 {"is_in_prefader", (PyCFunction)OutputChannel_is_in_prefader, METH_VARARGS, "Is a channel set as prefader"},
874 {NULL}
877 static PyTypeObject OutputChannelType = {
878 PyVarObject_HEAD_INIT(NULL, 0)
879 "jack_mixer_c.OutputChannel", /*tp_name*/
880 sizeof(OutputChannelObject), /*tp_basicsize*/
881 0, /*tp_itemsize*/
882 0, /*tp_dealloc*/
883 0, /*tp_print*/
884 0, /*tp_getattr*/
885 0, /*tp_setattr*/
886 0, /*tp_compare*/
887 0, /*tp_repr*/
888 0, /*tp_as_number*/
889 0, /*tp_as_sequence*/
890 0, /*tp_as_mapping*/
891 0, /*tp_hash */
892 0, /*tp_call*/
893 0, /*tp_str*/
894 0, /*tp_getattro*/
895 0, /*tp_setattro*/
896 0, /*tp_as_buffer*/
897 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
898 "Output Channel objects", /* tp_doc */
899 0, /* tp_traverse */
900 0, /* tp_clear */
901 0, /* tp_richcompare */
902 0, /* tp_weaklistoffset */
903 0, /* tp_iter */
904 0, /* tp_iternext */
905 output_channel_methods, /* tp_methods */
906 0, /* tp_members */
907 OutputChannel_getseters, /* tp_getset */
908 &ChannelType, /* tp_base */
909 0, /* tp_dict */
910 0, /* tp_descr_get */
911 0, /* tp_descr_set */
912 0, /* tp_dictoffset */
913 0, /* tp_init */
914 0, /* tp_alloc */
915 0, /* tp_new */
918 static PyObject*
919 OutputChannel_New(jack_mixer_output_channel_t output_channel)
921 OutputChannelObject *self;
922 self = (OutputChannelObject*)PyObject_NEW(OutputChannelObject, &OutputChannelType);
923 if (self != NULL) {
924 self->midi_change_callback = NULL;
925 self->output_channel = output_channel;
927 return (PyObject*)self;
931 /** Mixer Type **/
933 typedef struct {
934 PyObject_HEAD
935 jack_mixer_t mixer;
936 } MixerObject;
938 static void
939 Mixer_dealloc(MixerObject *self)
941 if (self->mixer)
942 destroy(self->mixer);
943 Py_TYPE(self)->tp_free((PyObject*)self);
946 static PyObject*
947 Mixer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
949 MixerObject *self;
951 self = (MixerObject*)type->tp_alloc(type, 0);
953 if (self != NULL) {
954 self->mixer = NULL;
957 return (PyObject*)self;
960 static int
961 Mixer_init(MixerObject *self, PyObject *args, PyObject *kwds)
963 static char *kwlist[] = {"name", "stereo", NULL};
964 char *name;
965 int stereo = 1;
967 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|b", kwlist, &name, &stereo))
968 return -1;
970 self->mixer = create(name, (bool)stereo);
971 if (self->mixer == NULL) {
972 PyErr_SetString(PyExc_RuntimeError,
973 "error creating mixer, probably jack is not running");
974 return -1;
977 return 0;
980 static PyMemberDef Mixer_members[] = {
981 {NULL}
984 static PyObject*
985 Mixer_get_channels_count(MixerObject *self, void *closure)
987 return PyLong_FromLong(get_channels_count(self->mixer));
990 static PyObject*
991 Mixer_get_client_name(MixerObject *self, void *closure)
993 return PyUnicode_FromString(get_client_name(self->mixer));
996 static PyObject*
997 Mixer_get_last_midi_cc(MixerObject *self, void *closure)
999 return PyLong_FromLong(get_last_midi_cc(self->mixer));
1002 static int
1003 Mixer_set_last_midi_cc(MixerObject *self, PyObject *value, void *closure)
1005 int new_cc;
1006 unsigned int result;
1008 new_cc = PyLong_AsLong(value);
1009 result = set_last_midi_cc(self->mixer, (int8_t)new_cc);
1010 if (result == 0) {
1011 return 0;
1013 return -1;
1016 static PyObject*
1017 Mixer_get_midi_behavior_mode(MixerObject *self, void *closure)
1019 return PyLong_FromLong(get_midi_behavior_mode(self->mixer));
1022 static int
1023 Mixer_set_midi_behavior_mode(MixerObject *self, PyObject *value, void *closure)
1025 int mode;
1026 unsigned int result;
1028 mode = PyLong_AsLong(value);
1029 result = set_midi_behavior_mode(self->mixer, mode);
1030 if (result == 0) {
1031 return 0;
1033 return -1;
1038 static PyGetSetDef Mixer_getseters[] = {
1039 {"channels_count", (getter)Mixer_get_channels_count, NULL,
1040 "channels count", NULL},
1041 {"last_midi_cc", (getter)Mixer_get_last_midi_cc, (setter)Mixer_set_last_midi_cc,
1042 "last midi channel", NULL},
1043 {"midi_behavior_mode", (getter)Mixer_get_midi_behavior_mode, (setter)Mixer_set_midi_behavior_mode,
1044 "midi behavior mode", NULL},
1045 {NULL}
1048 static PyObject*
1049 Mixer_add_channel(MixerObject *self, PyObject *args)
1051 char *name;
1052 int stereo;
1053 jack_mixer_channel_t channel;
1055 if (! PyArg_ParseTuple(args, "si", &name, &stereo)) return NULL;
1057 channel = add_channel(self->mixer, name, (bool)stereo);
1059 if (channel == NULL) {
1060 PyErr_SetString(PyExc_RuntimeError, "error adding channel");
1061 return NULL;
1064 return Channel_New(channel);
1067 static PyObject*
1068 Mixer_add_output_channel(MixerObject *self, PyObject *args)
1070 char *name;
1071 int stereo = 1;
1072 int system = 0;
1073 jack_mixer_output_channel_t channel;
1075 if (! PyArg_ParseTuple(args, "s|bb", &name, &stereo, &system)) return NULL;
1077 channel = add_output_channel(self->mixer, name, (bool)stereo, (bool)system);
1079 return OutputChannel_New(channel);
1082 static PyObject*
1083 Mixer_destroy(MixerObject *self, PyObject *args)
1085 if (self->mixer) {
1086 destroy(self->mixer);
1087 self->mixer = NULL;
1089 Py_INCREF(Py_None);
1090 return Py_None;
1093 static PyMethodDef Mixer_methods[] = {
1094 {"add_channel", (PyCFunction)Mixer_add_channel, METH_VARARGS, "Add a new channel"},
1095 {"add_output_channel", (PyCFunction)Mixer_add_output_channel, METH_VARARGS, "Add a new output channel"},
1096 {"destroy", (PyCFunction)Mixer_destroy, METH_VARARGS, "Destroy JACK Mixer"},
1097 {"client_name", (PyCFunction)Mixer_get_client_name, METH_VARARGS, "Get jack client name"},
1098 // {"remove_channel", (PyCFunction)Mixer_remove_channel, METH_VARARGS, "Remove a channel"},
1099 {NULL}
1102 static PyTypeObject MixerType = {
1103 PyVarObject_HEAD_INIT(NULL, 0)
1104 "jack_mixer_c.Mixer", /*tp_name*/
1105 sizeof(MixerObject), /*tp_basicsize*/
1106 0, /*tp_itemsize*/
1107 (destructor)Mixer_dealloc, /*tp_dealloc*/
1108 0, /*tp_print*/
1109 0, /*tp_getattr*/
1110 0, /*tp_setattr*/
1111 0, /*tp_compare*/
1112 0, /*tp_repr*/
1113 0, /*tp_as_number*/
1114 0, /*tp_as_sequence*/
1115 0, /*tp_as_mapping*/
1116 0, /*tp_hash */
1117 0, /*tp_call*/
1118 0, /*tp_str*/
1119 0, /*tp_getattro*/
1120 0, /*tp_setattro*/
1121 0, /*tp_as_buffer*/
1122 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1123 "Mixer objects", /* tp_doc */
1124 0, /* tp_traverse */
1125 0, /* tp_clear */
1126 0, /* tp_richcompare */
1127 0, /* tp_weaklistoffset */
1128 0, /* tp_iter */
1129 0, /* tp_iternext */
1130 Mixer_methods, /* tp_methods */
1131 Mixer_members, /* tp_members */
1132 Mixer_getseters, /* tp_getset */
1133 0, /* tp_base */
1134 0, /* tp_dict */
1135 0, /* tp_descr_get */
1136 0, /* tp_descr_set */
1137 0, /* tp_dictoffset */
1138 (initproc)Mixer_init, /* tp_init */
1139 0, /* tp_alloc */
1140 Mixer_new, /* tp_new */
1144 static PyMethodDef jack_mixer_methods[] = {
1145 {NULL, NULL, 0, NULL} /* Sentinel */
1149 static struct PyModuleDef moduledef = {
1150 PyModuleDef_HEAD_INIT,
1151 "jack_mixer_c", /* m_name */
1152 "Jack Mixer C Helper Module", /* m_doc */
1153 -1, /* m_size */
1154 jack_mixer_methods, /* m_methods */
1155 NULL, /* m_reload */
1156 NULL, /* m_traverse */
1157 NULL, /* m_clear */
1158 NULL, /* m_free */
1161 PyMODINIT_FUNC PyInit_jack_mixer_c(void)
1163 PyObject *m;
1165 if (PyType_Ready(&MixerType) < 0)
1166 return NULL;
1167 if (PyType_Ready(&ChannelType) < 0)
1168 return NULL;
1169 if (PyType_Ready(&OutputChannelType) < 0)
1170 return NULL;
1171 if (PyType_Ready(&ScaleType) < 0)
1172 return NULL;
1174 m = PyModule_Create(&moduledef);
1175 //m = Py_InitModule3("jack_mixer_c", jack_mixer_methods, "module doc");
1177 Py_INCREF(&MixerType);
1178 PyModule_AddObject(m, "Mixer", (PyObject*)&MixerType);
1179 Py_INCREF(&ChannelType);
1180 PyModule_AddObject(m, "Channel", (PyObject*)&ChannelType);
1181 Py_INCREF(&OutputChannelType);
1182 PyModule_AddObject(m, "OutputChannel", (PyObject*)&OutputChannelType);
1183 Py_INCREF(&ScaleType);
1184 PyModule_AddObject(m, "Scale", (PyObject*)&ScaleType);
1186 return m;