]> git.0d.be Git - jack_mixer.git/blob - jack_mixer_c.c
Add K20 scale
[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         channel_set_midi_cc_volume_picked_up(self->channel, false);
219         return 0;
220 }
221
222 static PyObject*
223 Channel_get_balance(ChannelObject *self, void *closure)
224 {
225         return PyFloat_FromDouble(channel_balance_read(self->channel));
226 }
227
228 static int
229 Channel_set_balance(ChannelObject *self, PyObject *value, void *closure)
230 {
231         channel_balance_write(self->channel, PyFloat_AsDouble(value));
232         channel_set_midi_cc_balance_picked_up(self->channel, false);
233         return 0;
234 }
235
236 static PyObject*
237 Channel_get_out_mute(ChannelObject *self, void *closure)
238 {
239         PyObject *result;
240
241         if (channel_is_out_muted(self->channel)) {
242                 result = Py_True;
243         } else {
244                 result = Py_False;
245         }
246         Py_INCREF(result);
247         return result;
248 }
249
250 static int
251 Channel_set_out_mute(ChannelObject *self, PyObject *value, void *closure)
252 {
253         if (value == Py_True) {
254                 channel_out_mute(self->channel);
255         } else {
256                 channel_out_unmute(self->channel);
257         }
258         return 0;
259 }
260
261 static PyObject*
262 Channel_get_solo(ChannelObject *self, void *closure)
263 {
264         PyObject *result;
265
266         if (channel_is_soloed(self->channel)) {
267                 result = Py_True;
268         } else {
269                 result = Py_False;
270         }
271         Py_INCREF(result);
272         return result;
273 }
274
275 static int
276 Channel_set_solo(ChannelObject *self, PyObject *value, void *closure)
277 {
278         if (value == Py_True) {
279                 channel_solo(self->channel);
280         } else {
281                 channel_unsolo(self->channel);
282         }
283         return 0;
284 }
285
286 static PyObject*
287 Channel_get_meter(ChannelObject *self, void *closure)
288 {
289         PyObject *result;
290         double left, right;
291
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));
301         }
302         return result;
303 }
304
305 static PyObject*
306 Channel_get_kmeter(ChannelObject *self, void *closure)
307 {
308         PyObject *result;
309         double peak_left, peak_right, rms_left, rms_right;
310
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));
323         }
324         return result;
325 }
326
327 static PyObject*
328 Channel_get_abspeak(ChannelObject *self, void *closure)
329 {
330         return PyFloat_FromDouble(channel_abspeak_read(self->channel));
331 }
332
333 static int
334 Channel_set_abspeak(ChannelObject *self, PyObject *value, void *closure)
335 {
336         if (value != Py_None) {
337                 fprintf(stderr, "abspeak can only be reset (set to None)\n");
338                 return -1;
339         }
340         channel_abspeak_reset(self->channel);
341         return 0;
342 }
343
344 static int
345 Channel_set_midi_scale(ChannelObject *self, PyObject *value, void *closure)
346 {
347         ScaleObject *scale_object = (ScaleObject*)value; /* XXX: check */
348
349         channel_set_midi_scale(self->channel, scale_object->scale);
350         return 0;
351 }
352
353
354 static PyObject*
355 Channel_get_midi_change_callback(ChannelObject *self, void *closure)
356 {
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;
363         }
364 }
365
366 static void
367 channel_midi_callback(void *userdata)
368 {
369         ChannelObject *self = (ChannelObject*)userdata;
370         PyGILState_STATE gstate;
371
372         gstate = PyGILState_Ensure();
373         PyObject_CallObject(self->midi_change_callback, NULL);
374         PyGILState_Release(gstate);
375 }
376
377 static int
378 Channel_set_midi_change_callback(ChannelObject *self, PyObject *value, void *closure)
379 {
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;
387                 }
388                 if (self->midi_change_callback) {
389                         Py_XDECREF(self->midi_change_callback);
390                 }
391                 Py_INCREF(value);
392                 self->midi_change_callback = value;
393                 channel_set_midi_change_callback(self->channel,
394                                 channel_midi_callback, self);
395         }
396
397         return 0;
398 }
399
400 static PyObject*
401 Channel_get_name(ChannelObject *self, void *closure)
402 {
403         return PyUnicode_FromString(channel_get_name(self->channel));
404 }
405
406 static int
407 Channel_set_name(ChannelObject *self, PyObject *value, void *closure)
408 {
409         channel_rename(self->channel, PyUnicode_AsUTF8(value));
410         return 0;
411 }
412
413 static PyObject*
414 Channel_get_balance_midi_cc(ChannelObject *self, void *closure)
415 {
416         return PyLong_FromLong(channel_get_balance_midi_cc(self->channel));
417 }
418
419 static int
420 Channel_set_balance_midi_cc(ChannelObject *self, PyObject *value, void *closure)
421 {
422         int new_cc;
423         unsigned int result;
424
425         new_cc = PyLong_AsLong(value);
426         result = channel_set_balance_midi_cc(self->channel, new_cc);
427         if (result == 0) {
428                 return 0;
429         }
430         if (result == 2) {
431                 PyErr_SetString(PyExc_RuntimeError, "value out of range");
432         }
433         return -1;
434 }
435
436 static PyObject*
437 Channel_get_volume_midi_cc(ChannelObject *self, void *closure)
438 {
439         return PyLong_FromLong(channel_get_volume_midi_cc(self->channel));
440 }
441
442 static int
443 Channel_set_volume_midi_cc(ChannelObject *self, PyObject *value, void *closure)
444 {
445         int new_cc;
446         unsigned int result;
447
448         new_cc = PyLong_AsLong(value);
449         result = channel_set_volume_midi_cc(self->channel, new_cc);
450         if (result == 0) {
451                 return 0;
452         }
453         if (result == 2) {
454                 PyErr_SetString(PyExc_RuntimeError, "value out of range");
455         }
456         return -1;
457 }
458
459 static PyObject*
460 Channel_get_mute_midi_cc(ChannelObject *self, void *closure)
461 {
462         return PyLong_FromLong(channel_get_mute_midi_cc(self->channel));
463 }
464
465 static int
466 Channel_set_mute_midi_cc(ChannelObject *self, PyObject *value, void *closure)
467 {
468         int new_cc;
469         unsigned int result;
470
471         new_cc = PyLong_AsLong(value);
472         result = channel_set_mute_midi_cc(self->channel, new_cc);
473         if (result == 0) {
474                 return 0;
475         }
476         if (result == 2) {
477                 PyErr_SetString(PyExc_RuntimeError, "value out of range");
478         }
479         return -1;
480 }
481
482 static PyObject*
483 Channel_get_solo_midi_cc(ChannelObject *self, void *closure)
484 {
485         return PyLong_FromLong(channel_get_solo_midi_cc(self->channel));
486 }
487
488 static int
489 Channel_set_solo_midi_cc(ChannelObject *self, PyObject *value, void *closure)
490 {
491         int new_cc;
492         unsigned int result;
493
494         new_cc = PyLong_AsLong(value);
495         result = channel_set_solo_midi_cc(self->channel, new_cc);
496         if (result == 0) {
497                 return 0;
498         }
499         if (result == 2) {
500                 PyErr_SetString(PyExc_RuntimeError, "value out of range");
501         }
502         return -1;
503 }
504
505 static PyObject*
506 Channel_get_midi_in_got_events(ChannelObject *self, void *closure)
507 {
508         PyObject *result;
509
510         if (channel_get_midi_in_got_events(self->channel)) {
511                 result = Py_True;
512         } else {
513                 result = Py_False;
514         }
515         Py_INCREF(result);
516         return result;
517 }
518
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}
575 };
576
577 static PyObject*
578 Channel_remove(ChannelObject *self, PyObject *args)
579 {
580         if (! PyArg_ParseTuple(args, "")) return NULL;
581         remove_channel(self->channel);
582         Py_INCREF(Py_None);
583         return Py_None;
584 }
585
586 static PyObject*
587 Channel_autoset_volume_midi_cc(ChannelObject *self, PyObject *args)
588 {
589         if (! PyArg_ParseTuple(args, "")) return NULL;
590         channel_autoset_volume_midi_cc(self->channel);
591         Py_INCREF(Py_None);
592         return Py_None;
593 }
594
595 static PyObject*
596 Channel_autoset_balance_midi_cc(ChannelObject *self, PyObject *args)
597 {
598         if (! PyArg_ParseTuple(args, "")) return NULL;
599         channel_autoset_balance_midi_cc(self->channel);
600         Py_INCREF(Py_None);
601         return Py_None;
602 }
603
604 static PyObject*
605 Channel_autoset_mute_midi_cc(ChannelObject *self, PyObject *args)
606 {
607         if (! PyArg_ParseTuple(args, "")) return NULL;
608         channel_autoset_mute_midi_cc(self->channel);
609         Py_INCREF(Py_None);
610         return Py_None;
611 }
612
613 static PyObject*
614 Channel_autoset_solo_midi_cc(ChannelObject *self, PyObject *args)
615 {
616         if (! PyArg_ParseTuple(args, "")) return NULL;
617         channel_autoset_solo_midi_cc(self->channel);
618         Py_INCREF(Py_None);
619         return Py_None;
620 }
621
622 static PyMethodDef channel_methods[] = {
623         {"remove", (PyCFunction)Channel_remove, METH_VARARGS, "Remove"},
624         {"autoset_volume_midi_cc",
625                 (PyCFunction)Channel_autoset_volume_midi_cc, METH_VARARGS, "Autoset Volume MIDI CC"},
626         {"autoset_balance_midi_cc",
627                 (PyCFunction)Channel_autoset_balance_midi_cc, METH_VARARGS, "Autoset Balance MIDI CC"},
628         {"autoset_mute_midi_cc",
629                 (PyCFunction)Channel_autoset_mute_midi_cc, METH_VARARGS, "Autoset Mute MIDI CC"},
630         {"autoset_solo_midi_cc",
631                 (PyCFunction)Channel_autoset_solo_midi_cc, METH_VARARGS, "Autoset Solo MIDI CC"},
632         {NULL}
633 };
634
635 static PyTypeObject ChannelType = {
636         PyVarObject_HEAD_INIT(NULL, 0)
637         "jack_mixer_c.Channel",    /*tp_name*/
638         sizeof(ChannelObject), /*tp_basicsize*/
639         0,       /*tp_itemsize*/
640         (destructor)Channel_dealloc,       /*tp_dealloc*/
641         0,       /*tp_print*/
642         0,       /*tp_getattr*/
643         0,       /*tp_setattr*/
644         0,       /*tp_compare*/
645         0,       /*tp_repr*/
646         0,       /*tp_as_number*/
647         0,       /*tp_as_sequence*/
648         0,       /*tp_as_mapping*/
649         0,       /*tp_hash */
650         0,       /*tp_call*/
651         0,       /*tp_str*/
652         0,       /*tp_getattro*/
653         0,       /*tp_setattro*/
654         0,       /*tp_as_buffer*/
655         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
656         "Channel objects",           /* tp_doc */
657         0,                         /* tp_traverse */
658         0,                         /* tp_clear */
659         0,                         /* tp_richcompare */
660         0,                         /* tp_weaklistoffset */
661         0,                         /* tp_iter */
662         0,                         /* tp_iternext */
663         channel_methods,           /* tp_methods */
664         0,             /* tp_members */
665         Channel_getseters,           /* tp_getset */
666         0,                         /* tp_base */
667         0,                         /* tp_dict */
668         0,                         /* tp_descr_get */
669         0,                         /* tp_descr_set */
670         0,                         /* tp_dictoffset */
671         (initproc)Channel_init,    /* tp_init */
672         0,                         /* tp_alloc */
673         Channel_new,                 /* tp_new */
674 };
675
676 static PyObject*
677 Channel_New(jack_mixer_channel_t channel)
678 {
679         ChannelObject *self;
680         self = (ChannelObject*)PyObject_NEW(ChannelObject, &ChannelType);
681         if (self != NULL) {
682                 self->channel = channel;
683                 self->midi_change_callback = NULL;
684         }
685         return (PyObject*)self;
686 }
687
688 /** Output Channel Type **/
689
690 typedef struct {
691         PyObject_HEAD
692         PyObject *midi_change_callback;
693         jack_mixer_output_channel_t *output_channel;
694 } OutputChannelObject;
695
696 static int
697 OutputChannel_set_prefader(OutputChannelObject *self, PyObject *value, void *closure)
698 {
699         if (value == Py_True) {
700                 output_channel_set_prefader(self->output_channel, true);
701         } else {
702                 output_channel_set_prefader(self->output_channel, false);
703         }
704         return 0;
705 }
706
707 static PyObject*
708 OutputChannel_get_prefader(OutputChannelObject *self, void *closure)
709 {
710         PyObject *result;
711
712         if (output_channel_is_prefader(self->output_channel)) {
713                 result = Py_True;
714         } else {
715                 result = Py_False;
716         }
717         Py_INCREF(result);
718         return result;
719 }
720
721 static PyGetSetDef OutputChannel_getseters[] = {
722         {"prefader",
723                 (getter)OutputChannel_get_prefader, (setter)OutputChannel_set_prefader,
724                 "prefader", NULL},
725         {NULL}
726 };
727
728 static PyObject*
729 OutputChannel_remove(OutputChannelObject *self, PyObject *args)
730 {
731         if (! PyArg_ParseTuple(args, "")) return NULL;
732         remove_output_channel(self->output_channel);
733         Py_INCREF(Py_None);
734         return Py_None;
735 }
736
737 static PyObject*
738 OutputChannel_set_solo(OutputChannelObject *self, PyObject *args)
739 {
740         PyObject *channel;
741         unsigned char solo;
742
743         if (! PyArg_ParseTuple(args, "Ob", &channel, &solo)) return NULL;
744
745         output_channel_set_solo(self->output_channel,
746                         ((ChannelObject*)channel)->channel,
747                         solo);
748
749         Py_INCREF(Py_None);
750         return Py_None;
751 }
752
753 static PyObject*
754 OutputChannel_set_muted(OutputChannelObject *self, PyObject *args)
755 {
756         PyObject *channel;
757         unsigned char muted;
758
759         if (! PyArg_ParseTuple(args, "Ob", &channel, &muted)) return NULL;
760
761         output_channel_set_muted(self->output_channel,
762                         ((ChannelObject*)channel)->channel,
763                         muted);
764
765         Py_INCREF(Py_None);
766         return Py_None;
767 }
768
769 static PyObject*
770 OutputChannel_is_solo(OutputChannelObject *self, PyObject *args)
771 {
772         PyObject *channel;
773         PyObject *result;
774
775         if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
776
777         if (output_channel_is_solo(self->output_channel,
778                         ((ChannelObject*)channel)->channel)) {
779                 result = Py_True;
780         } else {
781                 result = Py_False;
782         }
783
784         Py_INCREF(result);
785         return result;
786 }
787
788 static PyObject*
789 OutputChannel_is_muted(OutputChannelObject *self, PyObject *args)
790 {
791         PyObject *channel;
792         PyObject *result;
793
794         if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
795
796         if (output_channel_is_muted(self->output_channel,
797                         ((ChannelObject*)channel)->channel)) {
798                 result = Py_True;
799         } else {
800                 result = Py_False;
801         }
802
803         Py_INCREF(result);
804         return result;
805 }
806
807 static PyObject*
808 OutputChannel_set_in_prefader(OutputChannelObject *self, PyObject *args)
809 {
810         PyObject *channel;
811         unsigned char prefader;
812
813         if (! PyArg_ParseTuple(args, "Ob", &channel, &prefader)) return NULL;
814
815         output_channel_set_in_prefader(self->output_channel,
816                         ((ChannelObject*)channel)->channel,
817                         prefader);
818
819         Py_INCREF(Py_None);
820         return Py_None;
821 }
822
823 static PyObject*
824 OutputChannel_is_in_prefader(OutputChannelObject *self, PyObject *args)
825 {
826         PyObject *channel;
827         PyObject *result;
828
829         if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
830
831         if (output_channel_is_in_prefader(self->output_channel,
832                         ((ChannelObject*)channel)->channel)) {
833                 result = Py_True;
834         } else {
835                 result = Py_False;
836         }
837
838         Py_INCREF(result);
839         return result;
840 }
841
842 static PyMethodDef output_channel_methods[] = {
843         {"remove", (PyCFunction)OutputChannel_remove, METH_VARARGS, "Remove"},
844         {"set_solo", (PyCFunction)OutputChannel_set_solo, METH_VARARGS, "Set a channel as solo"},
845         {"set_muted", (PyCFunction)OutputChannel_set_muted, METH_VARARGS, "Set a channel as muted"},
846         {"is_solo", (PyCFunction)OutputChannel_is_solo, METH_VARARGS, "Is a channel set as solo"},
847         {"is_muted", (PyCFunction)OutputChannel_is_muted, METH_VARARGS, "Is a channel set as muted"},
848         {"set_in_prefader", (PyCFunction)OutputChannel_set_in_prefader, METH_VARARGS, "Set a channel as prefader"},
849         {"is_in_prefader", (PyCFunction)OutputChannel_is_in_prefader, METH_VARARGS, "Is a channel set as prefader"},
850         {NULL}
851 };
852
853 static PyTypeObject OutputChannelType = {
854         PyVarObject_HEAD_INIT(NULL, 0)
855         "jack_mixer_c.OutputChannel",    /*tp_name*/
856         sizeof(OutputChannelObject), /*tp_basicsize*/
857         0,       /*tp_itemsize*/
858         0,       /*tp_dealloc*/
859         0,       /*tp_print*/
860         0,       /*tp_getattr*/
861         0,       /*tp_setattr*/
862         0,       /*tp_compare*/
863         0,       /*tp_repr*/
864         0,       /*tp_as_number*/
865         0,       /*tp_as_sequence*/
866         0,       /*tp_as_mapping*/
867         0,       /*tp_hash */
868         0,       /*tp_call*/
869         0,       /*tp_str*/
870         0,       /*tp_getattro*/
871         0,       /*tp_setattro*/
872         0,       /*tp_as_buffer*/
873         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
874         "Output Channel objects",           /* tp_doc */
875         0,                         /* tp_traverse */
876         0,                         /* tp_clear */
877         0,                         /* tp_richcompare */
878         0,                         /* tp_weaklistoffset */
879         0,                         /* tp_iter */
880         0,                         /* tp_iternext */
881         output_channel_methods,    /* tp_methods */
882         0,             /* tp_members */
883         OutputChannel_getseters,   /* tp_getset */
884         &ChannelType,              /* tp_base */
885         0,                         /* tp_dict */
886         0,                         /* tp_descr_get */
887         0,                         /* tp_descr_set */
888         0,                         /* tp_dictoffset */
889         0,                         /* tp_init */
890         0,                         /* tp_alloc */
891         0,                         /* tp_new */
892 };
893
894 static PyObject*
895 OutputChannel_New(jack_mixer_output_channel_t output_channel)
896 {
897         OutputChannelObject *self;
898         self = (OutputChannelObject*)PyObject_NEW(OutputChannelObject, &OutputChannelType);
899         if (self != NULL) {
900                 self->midi_change_callback = NULL;
901                 self->output_channel = output_channel;
902         }
903         return (PyObject*)self;
904 }
905
906
907 /** Mixer Type **/
908
909 typedef struct {
910         PyObject_HEAD
911         jack_mixer_t mixer;
912 } MixerObject;
913
914 static void
915 Mixer_dealloc(MixerObject *self)
916 {
917         if (self->mixer)
918                 destroy(self->mixer);
919         Py_TYPE(self)->tp_free((PyObject*)self);
920 }
921
922 static PyObject*
923 Mixer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
924 {
925         MixerObject *self;
926
927         self = (MixerObject*)type->tp_alloc(type, 0);
928
929         if (self != NULL) {
930                 self->mixer = NULL;
931         }
932
933         return (PyObject*)self;
934 }
935
936 static int
937 Mixer_init(MixerObject *self, PyObject *args, PyObject *kwds)
938 {
939         static char *kwlist[] = {"name", "stereo", NULL};
940         char *name;
941         int stereo = 1;
942
943         if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|b", kwlist, &name, &stereo))
944                 return -1;
945
946         self->mixer = create(name, (bool)stereo);
947         if (self->mixer == NULL) {
948                 PyErr_SetString(PyExc_RuntimeError,
949                                 "error creating mixer, probably jack is not running");
950                 return -1;
951         }
952
953         return 0;
954 }
955
956 static PyMemberDef Mixer_members[] = {
957         {NULL}
958 };
959
960 static PyObject*
961 Mixer_get_channels_count(MixerObject *self, void *closure)
962 {
963         return PyLong_FromLong(get_channels_count(self->mixer));
964 }
965
966 static PyObject*
967 Mixer_get_client_name(MixerObject *self, void *closure)
968 {
969         return PyUnicode_FromString(get_client_name(self->mixer));
970 }
971
972 static PyObject*
973 Mixer_get_last_midi_channel(MixerObject *self, void *closure)
974 {
975         return PyLong_FromLong(get_last_midi_channel(self->mixer));
976 }
977
978 static int
979 Mixer_set_last_midi_channel(MixerObject *self, PyObject *value, void *closure)
980 {
981         int new_channel;
982         unsigned int result;
983
984         new_channel = PyLong_AsLong(value);
985         result = set_last_midi_channel(self->mixer, new_channel);
986         if (result == 0) {
987                 return 0;
988         }
989         return -1;
990 }
991
992 static PyObject*
993 Mixer_get_midi_behavior_mode(MixerObject *self, void *closure)
994 {
995         return PyLong_FromLong(get_midi_behavior_mode(self->mixer));
996 }
997
998 static int
999 Mixer_set_midi_behavior_mode(MixerObject *self, PyObject *value, void *closure)
1000 {
1001         int mode;
1002         unsigned int result;
1003         
1004         mode = PyLong_AsLong(value);
1005         result = set_midi_behavior_mode(self->mixer, mode);
1006         if (result == 0) {
1007                 return 0;
1008         }
1009         return -1;
1010 }
1011
1012
1013
1014 static PyGetSetDef Mixer_getseters[] = {
1015         {"channels_count", (getter)Mixer_get_channels_count, NULL,
1016                 "channels count", NULL},
1017         {"last_midi_channel", (getter)Mixer_get_last_midi_channel, (setter)Mixer_set_last_midi_channel,
1018                 "last midi channel", NULL},
1019         {"midi_behavior_mode", (getter)Mixer_get_midi_behavior_mode, (setter)Mixer_set_midi_behavior_mode,
1020                 "midi behavior mode", NULL},
1021         {NULL}
1022 };
1023
1024 static PyObject*
1025 Mixer_add_channel(MixerObject *self, PyObject *args)
1026 {
1027         char *name;
1028         int stereo;
1029         jack_mixer_channel_t channel;
1030
1031         if (! PyArg_ParseTuple(args, "si", &name, &stereo)) return NULL;
1032
1033         channel = add_channel(self->mixer, name, (bool)stereo);
1034
1035         if (channel == NULL) {
1036                 PyErr_SetString(PyExc_RuntimeError, "error adding channel");
1037                 return NULL;
1038         }
1039
1040         return Channel_New(channel);
1041 }
1042
1043 static PyObject*
1044 Mixer_add_output_channel(MixerObject *self, PyObject *args)
1045 {
1046         char *name;
1047         int stereo = 1;
1048         int system = 0;
1049         jack_mixer_output_channel_t channel;
1050
1051         if (! PyArg_ParseTuple(args, "s|bb", &name, &stereo, &system)) return NULL;
1052
1053         channel = add_output_channel(self->mixer, name, (bool)stereo, (bool)system);
1054
1055         return OutputChannel_New(channel);
1056 }
1057
1058 static PyObject*
1059 Mixer_destroy(MixerObject *self, PyObject *args)
1060 {
1061         if (self->mixer) {
1062                 destroy(self->mixer);
1063                 self->mixer = NULL;
1064         }
1065         Py_INCREF(Py_None);
1066         return Py_None;
1067 }
1068
1069 static PyMethodDef Mixer_methods[] = {
1070         {"add_channel", (PyCFunction)Mixer_add_channel, METH_VARARGS, "Add a new channel"},
1071         {"add_output_channel", (PyCFunction)Mixer_add_output_channel, METH_VARARGS, "Add a new output channel"},
1072         {"destroy", (PyCFunction)Mixer_destroy, METH_VARARGS, "Destroy JACK Mixer"},
1073         {"client_name", (PyCFunction)Mixer_get_client_name, METH_VARARGS, "Get jack client name"},
1074 //      {"remove_channel", (PyCFunction)Mixer_remove_channel, METH_VARARGS, "Remove a channel"},
1075         {NULL}
1076 };
1077
1078 static PyTypeObject MixerType = {
1079         PyVarObject_HEAD_INIT(NULL, 0)
1080         "jack_mixer_c.Mixer",    /*tp_name*/
1081         sizeof(MixerObject), /*tp_basicsize*/
1082         0,       /*tp_itemsize*/
1083         (destructor)Mixer_dealloc,       /*tp_dealloc*/
1084         0,       /*tp_print*/
1085         0,       /*tp_getattr*/
1086         0,       /*tp_setattr*/
1087         0,       /*tp_compare*/
1088         0,       /*tp_repr*/
1089         0,       /*tp_as_number*/
1090         0,       /*tp_as_sequence*/
1091         0,       /*tp_as_mapping*/
1092         0,       /*tp_hash */
1093         0,       /*tp_call*/
1094         0,       /*tp_str*/
1095         0,       /*tp_getattro*/
1096         0,       /*tp_setattro*/
1097         0,       /*tp_as_buffer*/
1098         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
1099         "Mixer objects",           /* tp_doc */
1100         0,                         /* tp_traverse */
1101         0,                         /* tp_clear */
1102         0,                         /* tp_richcompare */
1103         0,                         /* tp_weaklistoffset */
1104         0,                         /* tp_iter */
1105         0,                         /* tp_iternext */
1106         Mixer_methods,             /* tp_methods */
1107         Mixer_members,             /* tp_members */
1108         Mixer_getseters,           /* tp_getset */
1109         0,                         /* tp_base */
1110         0,                         /* tp_dict */
1111         0,                         /* tp_descr_get */
1112         0,                         /* tp_descr_set */
1113         0,                         /* tp_dictoffset */
1114         (initproc)Mixer_init,      /* tp_init */
1115         0,                         /* tp_alloc */
1116         Mixer_new,                 /* tp_new */
1117 };
1118
1119
1120 static PyMethodDef jack_mixer_methods[] = {
1121         {NULL, NULL, 0, NULL}  /* Sentinel */
1122 };
1123
1124
1125 static struct PyModuleDef moduledef = {
1126         PyModuleDef_HEAD_INIT,
1127         "jack_mixer_c",                /* m_name */
1128         "Jack Mixer C Helper Module",  /* m_doc */
1129         -1,                            /* m_size */
1130         jack_mixer_methods,            /* m_methods */
1131         NULL,                          /* m_reload */
1132         NULL,                          /* m_traverse */
1133         NULL,                          /* m_clear */
1134         NULL,                          /* m_free */
1135 };
1136
1137 PyMODINIT_FUNC PyInit_jack_mixer_c(void)
1138 {
1139         PyObject *m;
1140
1141         if (PyType_Ready(&MixerType) < 0)
1142                 return NULL;
1143         if (PyType_Ready(&ChannelType) < 0)
1144                 return NULL;
1145         if (PyType_Ready(&OutputChannelType) < 0)
1146                 return NULL;
1147         if (PyType_Ready(&ScaleType) < 0)
1148                 return NULL;
1149                 
1150         m = PyModule_Create(&moduledef);
1151         //m = Py_InitModule3("jack_mixer_c", jack_mixer_methods, "module doc");
1152         
1153         Py_INCREF(&MixerType);
1154         PyModule_AddObject(m, "Mixer", (PyObject*)&MixerType);
1155         Py_INCREF(&ChannelType);
1156         PyModule_AddObject(m, "Channel", (PyObject*)&ChannelType);
1157         Py_INCREF(&OutputChannelType);
1158         PyModule_AddObject(m, "OutputChannel", (PyObject*)&OutputChannelType);
1159         Py_INCREF(&ScaleType);
1160         PyModule_AddObject(m, "Scale", (PyObject*)&ScaleType);
1161         
1162         return m;
1163 }
1164