]> git.0d.be Git - jack_mixer.git/blob - jack_mixer_c.c
Rename "Autoset" to "Learn"
[jack_mixer.git] / jack_mixer_c.c
1 /*
2  * This file is part of jack_mixer
3  *
4  * Copyright (C) 2009 Frederic Peters <fpeters@0d.be>
5  *
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
9  *
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.
14  *
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.
18  */
19
20 #include <Python.h>
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdbool.h>
25
26 #include <structmember.h>
27
28 #include "jack_mixer.h"
29
30
31 /** Scale Type **/
32
33 typedef struct {
34         PyObject_HEAD
35         jack_mixer_scale_t scale;
36 } ScaleObject;
37
38 static void
39 Scale_dealloc(ScaleObject *self)
40 {
41         if (self->scale)
42                 scale_destroy(self->scale);
43         Py_TYPE(self)->tp_free((PyObject*)self);
44 }
45
46 static int
47 Scale_init(ScaleObject *self, PyObject *args, PyObject *kwds)
48 {
49         self->scale = scale_create();
50         return 0;
51 }
52
53 static PyObject*
54 Scale_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
55 {
56         ScaleObject *self;
57
58         self = (ScaleObject*)type->tp_alloc(type, 0);
59
60         return (PyObject*)self;
61 }
62
63 static PyObject*
64 Scale_add_threshold(ScaleObject *self, PyObject *args)
65 {
66         float db, scale_value;
67
68         if (! PyArg_ParseTuple(args, "ff", &db, &scale_value)) return NULL;
69
70         scale_add_threshold(self->scale, db, scale_value);
71
72         Py_INCREF(Py_None);
73         return Py_None;
74 }
75
76 static PyObject*
77 Scale_calculate_coefficients(ScaleObject *self, PyObject *args)
78 {
79         if (! PyArg_ParseTuple(args, "")) return NULL;
80         scale_calculate_coefficients(self->scale);
81         Py_INCREF(Py_None);
82         return Py_None;
83 }
84
85 static PyObject*
86 Scale_db_to_scale(ScaleObject *self, PyObject *args)
87 {
88         double db;
89         if (! PyArg_ParseTuple(args, "d", &db)) return NULL;
90         return PyFloat_FromDouble(scale_db_to_scale(self->scale, db));
91 }
92
93 static PyObject*
94 Scale_scale_to_db(ScaleObject *self, PyObject *args)
95 {
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));
99 }
100
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}
108 };
109
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 */
149 };
150
151
152 /** Channel Type **/
153
154 typedef struct {
155         PyObject_HEAD
156         PyObject *midi_change_callback;
157         jack_mixer_channel_t channel;
158 } ChannelObject;
159
160 static void
161 Channel_dealloc(ChannelObject *self)
162 {
163         Py_XDECREF(self->midi_change_callback);
164         Py_TYPE(self)->tp_free((PyObject*)self);
165 }
166
167 static int
168 Channel_init(ChannelObject *self, PyObject *args, PyObject *kwds)
169 {
170         self->midi_change_callback = NULL;
171         return 0;
172 }
173
174 static PyObject*
175 Channel_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
176 {
177         ChannelObject *self;
178
179         self = (ChannelObject*)type->tp_alloc(type, 0);
180
181         if (self != NULL) {
182                 self->channel = NULL;
183                 self->midi_change_callback = NULL;
184         }
185
186         return (PyObject*)self;
187 }
188
189 static PyObject*
190 Channel_get_is_stereo(ChannelObject *self, void *closure)
191 {
192         PyObject *result;
193
194         bool is_stereo = channel_is_stereo(self->channel);
195         if (is_stereo) {
196                 result = Py_True;
197         } else {
198                 result = Py_False;
199         }
200         Py_INCREF(result);
201         return result;
202 }
203
204 static PyObject*
205 Channel_get_volume(ChannelObject *self, void *closure)
206 {
207         return PyFloat_FromDouble(channel_volume_read(self->channel));
208 }
209
210 static int
211 Channel_set_volume(ChannelObject *self, PyObject *value, void *closure)
212 {
213         if (self->channel == NULL) {
214                 PyErr_SetString(PyExc_RuntimeError, "unitialized channel");
215                 return -1;
216         }
217         channel_volume_write(self->channel, PyFloat_AsDouble(value));
218         return 0;
219 }
220
221 static PyObject*
222 Channel_get_balance(ChannelObject *self, void *closure)
223 {
224         return PyFloat_FromDouble(channel_balance_read(self->channel));
225 }
226
227 static int
228 Channel_set_balance(ChannelObject *self, PyObject *value, void *closure)
229 {
230         channel_balance_write(self->channel, PyFloat_AsDouble(value));
231         return 0;
232 }
233
234 static PyObject*
235 Channel_get_out_mute(ChannelObject *self, void *closure)
236 {
237         PyObject *result;
238
239     if (channel_is_out_muted(self->channel)) {
240                 result = Py_True;
241         } else {
242                 result = Py_False;
243         }
244         Py_INCREF(result);
245         return result;
246 }
247
248 static int
249 Channel_set_out_mute(ChannelObject *self, PyObject *value, void *closure)
250 {
251         if (value == Py_True) {
252                 channel_out_mute(self->channel);
253         } else {
254                 channel_out_unmute(self->channel);
255         }
256         return 0;
257 }
258
259 static PyObject*
260 Channel_get_solo(ChannelObject *self, void *closure)
261 {
262         PyObject *result;
263
264         if (channel_is_soloed(self->channel)) {
265                 result = Py_True;
266         } else {
267                 result = Py_False;
268         }
269         Py_INCREF(result);
270         return result;
271 }
272
273 static int
274 Channel_set_solo(ChannelObject *self, PyObject *value, void *closure)
275 {
276         if (value == Py_True) {
277                 channel_solo(self->channel);
278         } else {
279                 channel_unsolo(self->channel);
280         }
281         return 0;
282 }
283
284 static PyObject*
285 Channel_get_meter(ChannelObject *self, void *closure)
286 {
287         PyObject *result;
288         double left, right;
289
290         if (channel_is_stereo(self->channel)) {
291                 result = PyTuple_New(2);
292                 channel_stereo_meter_read(self->channel, &left, &right);
293                 PyTuple_SetItem(result, 0, PyFloat_FromDouble(left));
294                 PyTuple_SetItem(result, 1, PyFloat_FromDouble(right));
295         } else {
296                 result = PyTuple_New(1);
297                 channel_mono_meter_read(self->channel, &left);
298                 PyTuple_SetItem(result, 0, PyFloat_FromDouble(left));
299         }
300         return result;
301 }
302
303 static PyObject*
304 Channel_get_abspeak(ChannelObject *self, void *closure)
305 {
306         return PyFloat_FromDouble(channel_abspeak_read(self->channel));
307 }
308
309 static int
310 Channel_set_abspeak(ChannelObject *self, PyObject *value, void *closure)
311 {
312         if (value != Py_None) {
313                 fprintf(stderr, "abspeak can only be reset (set to None)\n");
314                 return -1;
315         }
316         channel_abspeak_reset(self->channel);
317         return 0;
318 }
319
320 static int
321 Channel_set_midi_scale(ChannelObject *self, PyObject *value, void *closure)
322 {
323         ScaleObject *scale_object = (ScaleObject*)value; /* XXX: check */
324
325         channel_set_midi_scale(self->channel, scale_object->scale);
326         return 0;
327 }
328
329
330 static PyObject*
331 Channel_get_midi_change_callback(ChannelObject *self, void *closure)
332 {
333         if (self->midi_change_callback) {
334                 Py_INCREF(self->midi_change_callback);
335                 return self->midi_change_callback;
336         } else {
337                 Py_INCREF(Py_None);
338                 return Py_None;
339         }
340 }
341
342 static void
343 channel_midi_callback(void *userdata)
344 {
345         ChannelObject *self = (ChannelObject*)userdata;
346         PyGILState_STATE gstate;
347
348         gstate = PyGILState_Ensure();
349         PyObject_CallObject(self->midi_change_callback, NULL);
350         PyGILState_Release(gstate);
351 }
352
353 static int
354 Channel_set_midi_change_callback(ChannelObject *self, PyObject *value, void *closure)
355 {
356         if (value == Py_None) {
357                 self->midi_change_callback = NULL;
358                 channel_set_midi_change_callback(self->channel, NULL, NULL);
359         } else {
360                 if (!PyCallable_Check(value)) {
361                         PyErr_SetString(PyExc_TypeError, "value must be callable");
362                         return -1;
363                 }
364                 if (self->midi_change_callback) {
365                         Py_XDECREF(self->midi_change_callback);
366                 }
367                 Py_INCREF(value);
368                 self->midi_change_callback = value;
369                 channel_set_midi_change_callback(self->channel,
370                                 channel_midi_callback, self);
371         }
372
373         return 0;
374 }
375
376 static PyObject*
377 Channel_get_name(ChannelObject *self, void *closure)
378 {
379         return PyUnicode_FromString(channel_get_name(self->channel));
380 }
381
382 static int
383 Channel_set_name(ChannelObject *self, PyObject *value, void *closure)
384 {
385         channel_rename(self->channel, PyUnicode_AsUTF8(value));
386         return 0;
387 }
388
389 static PyObject*
390 Channel_get_balance_midi_cc(ChannelObject *self, void *closure)
391 {
392         return PyLong_FromLong(channel_get_balance_midi_cc(self->channel));
393 }
394
395 static int
396 Channel_set_balance_midi_cc(ChannelObject *self, PyObject *value, void *closure)
397 {
398         int new_cc;
399         unsigned int result;
400
401         new_cc = PyLong_AsLong(value);
402         result = channel_set_balance_midi_cc(self->channel, new_cc);
403         if (result == 0) {
404                 return 0;
405         }
406         if (result == 2) {
407                 PyErr_SetString(PyExc_RuntimeError, "value out of range");
408         }
409         return -1;
410 }
411
412 static PyObject*
413 Channel_get_volume_midi_cc(ChannelObject *self, void *closure)
414 {
415         return PyLong_FromLong(channel_get_volume_midi_cc(self->channel));
416 }
417
418 static int
419 Channel_set_volume_midi_cc(ChannelObject *self, PyObject *value, void *closure)
420 {
421         int new_cc;
422         unsigned int result;
423
424         new_cc = PyLong_AsLong(value);
425         result = channel_set_volume_midi_cc(self->channel, new_cc);
426         if (result == 0) {
427                 return 0;
428         }
429         if (result == 2) {
430                 PyErr_SetString(PyExc_RuntimeError, "value out of range");
431         }
432         return -1;
433 }
434
435 static PyObject*
436 Channel_get_mute_midi_cc(ChannelObject *self, void *closure)
437 {
438         return PyLong_FromLong(channel_get_mute_midi_cc(self->channel));
439 }
440
441 static int
442 Channel_set_mute_midi_cc(ChannelObject *self, PyObject *value, void *closure)
443 {
444         int new_cc;
445         unsigned int result;
446
447         new_cc = PyLong_AsLong(value);
448         result = channel_set_mute_midi_cc(self->channel, new_cc);
449         if (result == 0) {
450                 return 0;
451         }
452         if (result == 2) {
453                 PyErr_SetString(PyExc_RuntimeError, "value out of range");
454         }
455         return -1;
456 }
457
458 static PyObject*
459 Channel_get_solo_midi_cc(ChannelObject *self, void *closure)
460 {
461         return PyLong_FromLong(channel_get_solo_midi_cc(self->channel));
462 }
463
464 static int
465 Channel_set_solo_midi_cc(ChannelObject *self, PyObject *value, void *closure)
466 {
467         int new_cc;
468         unsigned int result;
469
470         new_cc = PyLong_AsLong(value);
471         result = channel_set_solo_midi_cc(self->channel, new_cc);
472         if (result == 0) {
473                 return 0;
474         }
475         if (result == 2) {
476                 PyErr_SetString(PyExc_RuntimeError, "value out of range");
477         }
478         return -1;
479 }
480
481 static PyObject*
482 Channel_get_midi_in_got_events(ChannelObject *self, void *closure)
483 {
484         PyObject *result;
485
486         if (channel_get_midi_in_got_events(self->channel)) {
487                 result = Py_True;
488         } else {
489                 result = Py_False;
490         }
491         Py_INCREF(result);
492         return result;
493 }
494
495 static PyGetSetDef Channel_getseters[] = {
496         {"is_stereo",
497                 (getter)Channel_get_is_stereo, NULL,
498                 "mono/stereo", NULL},
499         {"volume",
500                 (getter)Channel_get_volume, (setter)Channel_set_volume,
501                 "volume", NULL},
502         {"balance",
503                 (getter)Channel_get_balance, (setter)Channel_set_balance,
504                 "balance", NULL},
505         {"out_mute",
506                 (getter)Channel_get_out_mute, (setter)Channel_set_out_mute,
507                 "out_mute", NULL},
508         {"solo",
509                 (getter)Channel_get_solo, (setter)Channel_set_solo,
510                 "solo", NULL},
511         {"meter",
512                 (getter)Channel_get_meter, NULL,
513                 "meter", NULL},
514         {"abspeak",
515                 (getter)Channel_get_abspeak, (setter)Channel_set_abspeak,
516                 "balance", NULL},
517         {"midi_scale",
518                 NULL, (setter)Channel_set_midi_scale,
519                 "midi scale", NULL},
520         {"midi_change_callback",
521                 (getter)Channel_get_midi_change_callback,
522                 (setter)Channel_set_midi_change_callback,
523                 "midi change callback", NULL},
524         {"name",
525                 (getter)Channel_get_name,
526                 (setter)Channel_set_name,
527                 "name", NULL},
528         {"balance_midi_cc",
529                 (getter)Channel_get_balance_midi_cc,
530                 (setter)Channel_set_balance_midi_cc,
531                 "Balance MIDI CC", NULL},
532         {"volume_midi_cc",
533                 (getter)Channel_get_volume_midi_cc,
534                 (setter)Channel_set_volume_midi_cc,
535                 "Volume MIDI CC", NULL},
536         {"mute_midi_cc",
537                 (getter)Channel_get_mute_midi_cc,
538                 (setter)Channel_set_mute_midi_cc,
539                 "Mute MIDI CC", NULL},
540         {"solo_midi_cc",
541                 (getter)Channel_get_solo_midi_cc,
542                 (setter)Channel_set_solo_midi_cc,
543                 "Mute MIDI CC", NULL},
544         {"midi_in_got_events",
545                 (getter)Channel_get_midi_in_got_events, NULL,
546                 "Got new MIDI IN events", NULL},
547         {NULL}
548 };
549
550 static PyObject*
551 Channel_remove(ChannelObject *self, PyObject *args)
552 {
553         if (! PyArg_ParseTuple(args, "")) return NULL;
554         remove_channel(self->channel);
555         Py_INCREF(Py_None);
556         return Py_None;
557 }
558
559 static PyObject*
560 Channel_autoset_volume_midi_cc(ChannelObject *self, PyObject *args)
561 {
562         if (! PyArg_ParseTuple(args, "")) return NULL;
563         channel_autoset_volume_midi_cc(self->channel);
564         Py_INCREF(Py_None);
565         return Py_None;
566 }
567
568 static PyObject*
569 Channel_autoset_balance_midi_cc(ChannelObject *self, PyObject *args)
570 {
571         if (! PyArg_ParseTuple(args, "")) return NULL;
572         channel_autoset_balance_midi_cc(self->channel);
573         Py_INCREF(Py_None);
574         return Py_None;
575 }
576
577 static PyObject*
578 Channel_autoset_mute_midi_cc(ChannelObject *self, PyObject *args)
579 {
580         if (! PyArg_ParseTuple(args, "")) return NULL;
581         channel_autoset_mute_midi_cc(self->channel);
582         Py_INCREF(Py_None);
583         return Py_None;
584 }
585
586 static PyObject*
587 Channel_autoset_solo_midi_cc(ChannelObject *self, PyObject *args)
588 {
589         if (! PyArg_ParseTuple(args, "")) return NULL;
590         channel_autoset_solo_midi_cc(self->channel);
591         Py_INCREF(Py_None);
592         return Py_None;
593 }
594
595 static PyMethodDef channel_methods[] = {
596         {"remove", (PyCFunction)Channel_remove, METH_VARARGS, "Remove"},
597         {"autoset_volume_midi_cc",
598                 (PyCFunction)Channel_autoset_volume_midi_cc, METH_VARARGS, "Autoset Volume MIDI CC"},
599         {"autoset_balance_midi_cc",
600                 (PyCFunction)Channel_autoset_balance_midi_cc, METH_VARARGS, "Autoset Balance MIDI CC"},
601         {"autoset_mute_midi_cc",
602                 (PyCFunction)Channel_autoset_mute_midi_cc, METH_VARARGS, "Autoset Mute MIDI CC"},
603         {"autoset_solo_midi_cc",
604                 (PyCFunction)Channel_autoset_solo_midi_cc, METH_VARARGS, "Autoset Solo MIDI CC"},
605         {NULL}
606 };
607
608 static PyTypeObject ChannelType = {
609         PyVarObject_HEAD_INIT(NULL, 0)
610         "jack_mixer_c.Channel",    /*tp_name*/
611         sizeof(ChannelObject), /*tp_basicsize*/
612         0,       /*tp_itemsize*/
613         (destructor)Channel_dealloc,       /*tp_dealloc*/
614         0,       /*tp_print*/
615         0,       /*tp_getattr*/
616         0,       /*tp_setattr*/
617         0,       /*tp_compare*/
618         0,       /*tp_repr*/
619         0,       /*tp_as_number*/
620         0,       /*tp_as_sequence*/
621         0,       /*tp_as_mapping*/
622         0,       /*tp_hash */
623         0,       /*tp_call*/
624         0,       /*tp_str*/
625         0,       /*tp_getattro*/
626         0,       /*tp_setattro*/
627         0,       /*tp_as_buffer*/
628         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
629         "Channel objects",           /* tp_doc */
630         0,                         /* tp_traverse */
631         0,                         /* tp_clear */
632         0,                         /* tp_richcompare */
633         0,                         /* tp_weaklistoffset */
634         0,                         /* tp_iter */
635         0,                         /* tp_iternext */
636         channel_methods,           /* tp_methods */
637         0,             /* tp_members */
638         Channel_getseters,           /* tp_getset */
639         0,                         /* tp_base */
640         0,                         /* tp_dict */
641         0,                         /* tp_descr_get */
642         0,                         /* tp_descr_set */
643         0,                         /* tp_dictoffset */
644         (initproc)Channel_init,    /* tp_init */
645         0,                         /* tp_alloc */
646         Channel_new,                 /* tp_new */
647 };
648
649 static PyObject*
650 Channel_New(jack_mixer_channel_t channel)
651 {
652         ChannelObject *self;
653         self = (ChannelObject*)PyObject_NEW(ChannelObject, &ChannelType);
654         if (self != NULL) {
655                 self->channel = channel;
656                 self->midi_change_callback = NULL;
657         }
658         return (PyObject*)self;
659 }
660
661 /** Output Channel Type **/
662
663 typedef struct {
664         PyObject_HEAD
665         PyObject *midi_change_callback;
666         jack_mixer_output_channel_t *output_channel;
667 } OutputChannelObject;
668
669 static int
670 OutputChannel_set_prefader(OutputChannelObject *self, PyObject *value, void *closure)
671 {
672         if (value == Py_True) {
673                 output_channel_set_prefader(self->output_channel, true);
674         } else {
675                 output_channel_set_prefader(self->output_channel, false);
676         }
677         return 0;
678 }
679
680 static PyObject*
681 OutputChannel_get_prefader(OutputChannelObject *self, void *closure)
682 {
683         PyObject *result;
684
685         if (output_channel_is_prefader(self->output_channel)) {
686                 result = Py_True;
687         } else {
688                 result = Py_False;
689         }
690         Py_INCREF(result);
691         return result;
692 }
693
694 static PyGetSetDef OutputChannel_getseters[] = {
695         {"prefader",
696                 (getter)OutputChannel_get_prefader, (setter)OutputChannel_set_prefader,
697                 "prefader", NULL},
698         {NULL}
699 };
700
701 static PyObject*
702 OutputChannel_remove(OutputChannelObject *self, PyObject *args)
703 {
704         if (! PyArg_ParseTuple(args, "")) return NULL;
705         remove_output_channel(self->output_channel);
706         Py_INCREF(Py_None);
707         return Py_None;
708 }
709
710 static PyObject*
711 OutputChannel_set_solo(OutputChannelObject *self, PyObject *args)
712 {
713         PyObject *channel;
714         unsigned char solo;
715
716         if (! PyArg_ParseTuple(args, "Ob", &channel, &solo)) return NULL;
717
718         output_channel_set_solo(self->output_channel,
719                         ((ChannelObject*)channel)->channel,
720                         solo);
721
722         Py_INCREF(Py_None);
723         return Py_None;
724 }
725
726 static PyObject*
727 OutputChannel_set_muted(OutputChannelObject *self, PyObject *args)
728 {
729         PyObject *channel;
730         unsigned char muted;
731
732         if (! PyArg_ParseTuple(args, "Ob", &channel, &muted)) return NULL;
733
734         output_channel_set_muted(self->output_channel,
735                         ((ChannelObject*)channel)->channel,
736                         muted);
737
738         Py_INCREF(Py_None);
739         return Py_None;
740 }
741
742 static PyObject*
743 OutputChannel_is_solo(OutputChannelObject *self, PyObject *args)
744 {
745         PyObject *channel;
746         PyObject *result;
747
748         if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
749
750         if (output_channel_is_solo(self->output_channel,
751                         ((ChannelObject*)channel)->channel)) {
752                 result = Py_True;
753         } else {
754                 result = Py_False;
755         }
756
757         Py_INCREF(result);
758         return result;
759 }
760
761 static PyObject*
762 OutputChannel_is_muted(OutputChannelObject *self, PyObject *args)
763 {
764         PyObject *channel;
765         PyObject *result;
766
767         if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
768
769         if (output_channel_is_muted(self->output_channel,
770                         ((ChannelObject*)channel)->channel)) {
771                 result = Py_True;
772         } else {
773                 result = Py_False;
774         }
775
776         Py_INCREF(result);
777         return result;
778 }
779
780 static PyMethodDef output_channel_methods[] = {
781         {"remove", (PyCFunction)OutputChannel_remove, METH_VARARGS, "Remove"},
782         {"set_solo", (PyCFunction)OutputChannel_set_solo, METH_VARARGS, "Set a channel as solo"},
783         {"set_muted", (PyCFunction)OutputChannel_set_muted, METH_VARARGS, "Set a channel as muted"},
784         {"is_solo", (PyCFunction)OutputChannel_is_solo, METH_VARARGS, "Is a channel set as solo"},
785         {"is_muted", (PyCFunction)OutputChannel_is_muted, METH_VARARGS, "Is a channel set as muted"},
786         {NULL}
787 };
788
789 static PyTypeObject OutputChannelType = {
790         PyVarObject_HEAD_INIT(NULL, 0)
791         "jack_mixer_c.OutputChannel",    /*tp_name*/
792         sizeof(OutputChannelObject), /*tp_basicsize*/
793         0,       /*tp_itemsize*/
794         0,       /*tp_dealloc*/
795         0,       /*tp_print*/
796         0,       /*tp_getattr*/
797         0,       /*tp_setattr*/
798         0,       /*tp_compare*/
799         0,       /*tp_repr*/
800         0,       /*tp_as_number*/
801         0,       /*tp_as_sequence*/
802         0,       /*tp_as_mapping*/
803         0,       /*tp_hash */
804         0,       /*tp_call*/
805         0,       /*tp_str*/
806         0,       /*tp_getattro*/
807         0,       /*tp_setattro*/
808         0,       /*tp_as_buffer*/
809         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
810         "Output Channel objects",           /* tp_doc */
811         0,                         /* tp_traverse */
812         0,                         /* tp_clear */
813         0,                         /* tp_richcompare */
814         0,                         /* tp_weaklistoffset */
815         0,                         /* tp_iter */
816         0,                         /* tp_iternext */
817         output_channel_methods,    /* tp_methods */
818         0,             /* tp_members */
819         OutputChannel_getseters,   /* tp_getset */
820         &ChannelType,              /* tp_base */
821         0,                         /* tp_dict */
822         0,                         /* tp_descr_get */
823         0,                         /* tp_descr_set */
824         0,                         /* tp_dictoffset */
825         0,                         /* tp_init */
826         0,                         /* tp_alloc */
827         0,                         /* tp_new */
828 };
829
830 static PyObject*
831 OutputChannel_New(jack_mixer_output_channel_t output_channel)
832 {
833         OutputChannelObject *self;
834         self = (OutputChannelObject*)PyObject_NEW(OutputChannelObject, &OutputChannelType);
835         if (self != NULL) {
836                 self->midi_change_callback = NULL;
837                 self->output_channel = output_channel;
838         }
839         return (PyObject*)self;
840 }
841
842
843 /** Mixer Type **/
844
845 typedef struct {
846         PyObject_HEAD
847         jack_mixer_t mixer;
848 } MixerObject;
849
850 static void
851 Mixer_dealloc(MixerObject *self)
852 {
853         if (self->mixer)
854                 destroy(self->mixer);
855         Py_TYPE(self)->tp_free((PyObject*)self);
856 }
857
858 static PyObject*
859 Mixer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
860 {
861         MixerObject *self;
862
863         self = (MixerObject*)type->tp_alloc(type, 0);
864
865         if (self != NULL) {
866                 self->mixer = NULL;
867         }
868
869         return (PyObject*)self;
870 }
871
872 static int
873 Mixer_init(MixerObject *self, PyObject *args, PyObject *kwds)
874 {
875         static char *kwlist[] = {"name", "stereo", NULL};
876         char *name;
877         int stereo = 1;
878
879         if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|b", kwlist, &name, &stereo))
880                 return -1;
881
882         self->mixer = create(name, (bool)stereo);
883         if (self->mixer == NULL) {
884                 PyErr_SetString(PyExc_RuntimeError,
885                                 "error creating mixer, probably jack is not running");
886                 return -1;
887         }
888
889         return 0;
890 }
891
892 static PyMemberDef Mixer_members[] = {
893         {NULL}
894 };
895
896 static PyObject*
897 Mixer_get_channels_count(MixerObject *self, void *closure)
898 {
899         return PyLong_FromLong(get_channels_count(self->mixer));
900 }
901
902 static PyObject*
903 Mixer_get_client_name(MixerObject *self, void *closure)
904 {
905         return PyUnicode_FromString(get_client_name(self->mixer));
906 }
907
908 static PyObject*
909 Mixer_get_last_midi_channel(MixerObject *self, void *closure)
910 {
911         return PyLong_FromLong(get_last_midi_channel(self->mixer));
912 }
913
914 static int
915 Mixer_set_last_midi_channel(MixerObject *self, PyObject *value, void *closure)
916 {
917         int new_channel;
918         unsigned int result;
919
920         new_channel = PyLong_AsLong(value);
921         result = set_last_midi_channel(self->mixer, new_channel);
922         if (result == 0) {
923                 return 0;
924         }
925         return -1;
926 }
927
928 static PyGetSetDef Mixer_getseters[] = {
929         {"channels_count", (getter)Mixer_get_channels_count, NULL,
930                 "channels count", NULL},
931         {"last_midi_channel", (getter)Mixer_get_last_midi_channel, (setter)Mixer_set_last_midi_channel,
932                 "last midi channel", NULL},
933         {NULL}
934 };
935
936 static PyObject*
937 Mixer_add_channel(MixerObject *self, PyObject *args)
938 {
939         char *name;
940         int stereo;
941         jack_mixer_channel_t channel;
942
943         if (! PyArg_ParseTuple(args, "si", &name, &stereo)) return NULL;
944
945         channel = add_channel(self->mixer, name, (bool)stereo);
946
947         if (channel == NULL) {
948                 PyErr_SetString(PyExc_RuntimeError, "error adding channel");
949                 return NULL;
950         }
951
952         return Channel_New(channel);
953 }
954
955 static PyObject*
956 Mixer_add_output_channel(MixerObject *self, PyObject *args)
957 {
958         char *name;
959         int stereo = 1;
960         int system = 0;
961         jack_mixer_output_channel_t channel;
962
963         if (! PyArg_ParseTuple(args, "s|bb", &name, &stereo, &system)) return NULL;
964
965         channel = add_output_channel(self->mixer, name, (bool)stereo, (bool)system);
966
967         return OutputChannel_New(channel);
968 }
969
970 static PyObject*
971 Mixer_destroy(MixerObject *self, PyObject *args)
972 {
973         if (self->mixer) {
974                 destroy(self->mixer);
975                 self->mixer = NULL;
976         }
977         Py_INCREF(Py_None);
978         return Py_None;
979 }
980
981 static PyMethodDef Mixer_methods[] = {
982         {"add_channel", (PyCFunction)Mixer_add_channel, METH_VARARGS, "Add a new channel"},
983         {"add_output_channel", (PyCFunction)Mixer_add_output_channel, METH_VARARGS, "Add a new output channel"},
984         {"destroy", (PyCFunction)Mixer_destroy, METH_VARARGS, "Destroy JACK Mixer"},
985         {"client_name", (PyCFunction)Mixer_get_client_name, METH_VARARGS, "Get jack client name"},
986 //      {"remove_channel", (PyCFunction)Mixer_remove_channel, METH_VARARGS, "Remove a channel"},
987         {NULL}
988 };
989
990 static PyTypeObject MixerType = {
991         PyVarObject_HEAD_INIT(NULL, 0)
992         "jack_mixer_c.Mixer",    /*tp_name*/
993         sizeof(MixerObject), /*tp_basicsize*/
994         0,       /*tp_itemsize*/
995         (destructor)Mixer_dealloc,       /*tp_dealloc*/
996         0,       /*tp_print*/
997         0,       /*tp_getattr*/
998         0,       /*tp_setattr*/
999         0,       /*tp_compare*/
1000         0,       /*tp_repr*/
1001         0,       /*tp_as_number*/
1002         0,       /*tp_as_sequence*/
1003         0,       /*tp_as_mapping*/
1004         0,       /*tp_hash */
1005         0,       /*tp_call*/
1006         0,       /*tp_str*/
1007         0,       /*tp_getattro*/
1008         0,       /*tp_setattro*/
1009         0,       /*tp_as_buffer*/
1010         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
1011         "Mixer objects",           /* tp_doc */
1012         0,                         /* tp_traverse */
1013         0,                         /* tp_clear */
1014         0,                         /* tp_richcompare */
1015         0,                         /* tp_weaklistoffset */
1016         0,                         /* tp_iter */
1017         0,                         /* tp_iternext */
1018         Mixer_methods,             /* tp_methods */
1019         Mixer_members,             /* tp_members */
1020         Mixer_getseters,           /* tp_getset */
1021         0,                         /* tp_base */
1022         0,                         /* tp_dict */
1023         0,                         /* tp_descr_get */
1024         0,                         /* tp_descr_set */
1025         0,                         /* tp_dictoffset */
1026         (initproc)Mixer_init,      /* tp_init */
1027         0,                         /* tp_alloc */
1028         Mixer_new,                 /* tp_new */
1029 };
1030
1031
1032 static PyMethodDef jack_mixer_methods[] = {
1033         {NULL, NULL, 0, NULL}  /* Sentinel */
1034 };
1035
1036
1037 static struct PyModuleDef moduledef = {
1038         PyModuleDef_HEAD_INIT,
1039         "jack_mixer_c",                /* m_name */
1040         "Jack Mixer C Helper Module",  /* m_doc */
1041         -1,                            /* m_size */
1042         jack_mixer_methods,            /* m_methods */
1043         NULL,                          /* m_reload */
1044         NULL,                          /* m_traverse */
1045         NULL,                          /* m_clear */
1046         NULL,                          /* m_free */
1047 };
1048
1049 PyMODINIT_FUNC PyInit_jack_mixer_c(void)
1050 {
1051         PyObject *m;
1052
1053         if (PyType_Ready(&MixerType) < 0)
1054                 return NULL;
1055         if (PyType_Ready(&ChannelType) < 0)
1056                 return NULL;
1057         if (PyType_Ready(&OutputChannelType) < 0)
1058                 return NULL;
1059         if (PyType_Ready(&ScaleType) < 0)
1060                 return NULL;
1061                 
1062         m = PyModule_Create(&moduledef);
1063         //m = Py_InitModule3("jack_mixer_c", jack_mixer_methods, "module doc");
1064         
1065         Py_INCREF(&MixerType);
1066         PyModule_AddObject(m, "Mixer", (PyObject*)&MixerType);
1067         Py_INCREF(&ChannelType);
1068         PyModule_AddObject(m, "Channel", (PyObject*)&ChannelType);
1069         Py_INCREF(&OutputChannelType);
1070         PyModule_AddObject(m, "OutputChannel", (PyObject*)&OutputChannelType);
1071         Py_INCREF(&ScaleType);
1072         PyModule_AddObject(m, "Scale", (PyObject*)&ScaleType);
1073         
1074         return m;
1075 }
1076