]> git.0d.be Git - jack_mixer.git/blob - jack_mixer_c.c
Add per output channel mute button
[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         self->ob_type->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         PyObject_HEAD_INIT(NULL)
112         0,       /*ob_size*/
113         "jack_mixer_c.Scale",    /*tp_name*/
114         sizeof(ScaleObject), /*tp_basicsize*/
115         0,       /*tp_itemsize*/
116         (destructor)Scale_dealloc,       /*tp_dealloc*/
117         0,       /*tp_print*/
118         0,       /*tp_getattr*/
119         0,       /*tp_setattr*/
120         0,       /*tp_compare*/
121         0,       /*tp_repr*/
122         0,       /*tp_as_number*/
123         0,       /*tp_as_sequence*/
124         0,       /*tp_as_mapping*/
125         0,       /*tp_hash */
126         0,       /*tp_call*/
127         0,       /*tp_str*/
128         0,       /*tp_getattro*/
129         0,       /*tp_setattro*/
130         0,       /*tp_as_buffer*/
131         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
132         "Scale objects",           /* tp_doc */
133         0,                         /* tp_traverse */
134         0,                         /* tp_clear */
135         0,                         /* tp_richcompare */
136         0,                         /* tp_weaklistoffset */
137         0,                         /* tp_iter */
138         0,                         /* tp_iternext */
139         Scale_methods,             /* tp_methods */
140         0,             /* tp_members */
141         0,           /* tp_getset */
142         0,                         /* tp_base */
143         0,                         /* tp_dict */
144         0,                         /* tp_descr_get */
145         0,                         /* tp_descr_set */
146         0,                         /* tp_dictoffset */
147         (initproc)Scale_init,      /* tp_init */
148         0,                         /* tp_alloc */
149         Scale_new,                 /* tp_new */
150 };
151
152
153 /** Channel Type **/
154
155 typedef struct {
156         PyObject_HEAD
157         PyObject *midi_change_callback;
158         jack_mixer_channel_t channel;
159 } ChannelObject;
160
161 static void
162 Channel_dealloc(ChannelObject *self)
163 {
164         Py_XDECREF(self->midi_change_callback);
165         self->ob_type->tp_free((PyObject*)self);
166 }
167
168 static int
169 Channel_init(ChannelObject *self, PyObject *args, PyObject *kwds)
170 {
171         self->midi_change_callback = NULL;
172         return 0;
173 }
174
175 static PyObject*
176 Channel_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
177 {
178         ChannelObject *self;
179
180         self = (ChannelObject*)type->tp_alloc(type, 0);
181
182         if (self != NULL) {
183                 self->channel = NULL;
184                 self->midi_change_callback = NULL;
185         }
186
187         return (PyObject*)self;
188 }
189
190 static PyObject*
191 Channel_get_is_stereo(ChannelObject *self, void *closure)
192 {
193         PyObject *result;
194
195         bool is_stereo = channel_is_stereo(self->channel);
196         if (is_stereo) {
197                 result = Py_True;
198         } else {
199                 result = Py_False;
200         }
201         Py_INCREF(result);
202         return result;
203 }
204
205 static PyObject*
206 Channel_get_volume(ChannelObject *self, void *closure)
207 {
208         return PyFloat_FromDouble(channel_volume_read(self->channel));
209 }
210
211 static int
212 Channel_set_volume(ChannelObject *self, PyObject *value, void *closure)
213 {
214         if (self->channel == NULL) {
215                 PyErr_SetString(PyExc_RuntimeError, "unitialized channel");
216                 return -1;
217         }
218         channel_volume_write(self->channel, PyFloat_AsDouble(value));
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         return 0;
233 }
234
235 static PyObject*
236 Channel_get_mute(ChannelObject *self, void *closure)
237 {
238         PyObject *result;
239
240         if (channel_is_muted(self->channel)) {
241                 result = Py_True;
242         } else {
243                 result = Py_False;
244         }
245         Py_INCREF(result);
246         return result;
247 }
248
249 static PyObject*
250 Channel_get_out_mute(ChannelObject *self, void *closure)
251 {
252         PyObject *result;
253
254     if (channel_is_out_muted(self->channel)) {
255                 result = Py_True;
256         } else {
257                 result = Py_False;
258         }
259         Py_INCREF(result);
260         return result;
261 }
262
263 static int
264 Channel_set_mute(ChannelObject *self, PyObject *value, void *closure)
265 {
266         if (value == Py_True) {
267                 channel_mute(self->channel);
268         } else {
269                 channel_unmute(self->channel);
270         }
271         return 0;
272 }
273
274 static int
275 Channel_set_out_mute(ChannelObject *self, PyObject *value, void *closure)
276 {
277         if (value == Py_True) {
278                 channel_out_mute(self->channel);
279         } else {
280                 channel_out_unmute(self->channel);
281         }
282         return 0;
283 }
284
285 static PyObject*
286 Channel_get_solo(ChannelObject *self, void *closure)
287 {
288         PyObject *result;
289
290         if (channel_is_soloed(self->channel)) {
291                 result = Py_True;
292         } else {
293                 result = Py_False;
294         }
295         Py_INCREF(result);
296         return result;
297 }
298
299 static int
300 Channel_set_solo(ChannelObject *self, PyObject *value, void *closure)
301 {
302         if (value == Py_True) {
303                 channel_solo(self->channel);
304         } else {
305                 channel_unsolo(self->channel);
306         }
307         return 0;
308 }
309
310 static PyObject*
311 Channel_get_meter(ChannelObject *self, void *closure)
312 {
313         PyObject *result;
314         double left, right;
315
316         if (channel_is_stereo(self->channel)) {
317                 result = PyTuple_New(2);
318                 channel_stereo_meter_read(self->channel, &left, &right);
319                 PyTuple_SetItem(result, 0, PyFloat_FromDouble(left));
320                 PyTuple_SetItem(result, 1, PyFloat_FromDouble(right));
321         } else {
322                 result = PyTuple_New(1);
323                 channel_mono_meter_read(self->channel, &left);
324                 PyTuple_SetItem(result, 0, PyFloat_FromDouble(left));
325         }
326         return result;
327 }
328
329 static PyObject*
330 Channel_get_abspeak(ChannelObject *self, void *closure)
331 {
332         return PyFloat_FromDouble(channel_abspeak_read(self->channel));
333 }
334
335 static int
336 Channel_set_abspeak(ChannelObject *self, PyObject *value, void *closure)
337 {
338         if (value != Py_None) {
339                 fprintf(stderr, "abspeak can only be reset (set to None)\n");
340                 return -1;
341         }
342         channel_abspeak_reset(self->channel);
343         return 0;
344 }
345
346 static int
347 Channel_set_midi_scale(ChannelObject *self, PyObject *value, void *closure)
348 {
349         ScaleObject *scale_object = (ScaleObject*)value; /* XXX: check */
350
351         channel_set_midi_scale(self->channel, scale_object->scale);
352         return 0;
353 }
354
355
356 static PyObject*
357 Channel_get_midi_change_callback(ChannelObject *self, void *closure)
358 {
359         if (self->midi_change_callback) {
360                 Py_INCREF(self->midi_change_callback);
361                 return self->midi_change_callback;
362         } else {
363                 Py_INCREF(Py_None);
364                 return Py_None;
365         }
366 }
367
368 static void
369 channel_midi_callback(void *userdata)
370 {
371         ChannelObject *self = (ChannelObject*)userdata;
372         PyGILState_STATE gstate;
373
374         gstate = PyGILState_Ensure();
375         PyObject_CallObject(self->midi_change_callback, NULL);
376         PyGILState_Release(gstate);
377 }
378
379 static int
380 Channel_set_midi_change_callback(ChannelObject *self, PyObject *value, void *closure)
381 {
382         if (value == Py_None) {
383                 self->midi_change_callback = NULL;
384                 channel_set_midi_change_callback(self->channel, NULL, NULL);
385         } else {
386                 if (!PyCallable_Check(value)) {
387                         PyErr_SetString(PyExc_TypeError, "value must be callable");
388                         return -1;
389                 }
390                 if (self->midi_change_callback) {
391                         Py_XDECREF(self->midi_change_callback);
392                 }
393                 Py_INCREF(value);
394                 self->midi_change_callback = value;
395                 channel_set_midi_change_callback(self->channel,
396                                 channel_midi_callback, self);
397         }
398
399         return 0;
400 }
401
402 static PyObject*
403 Channel_get_name(ChannelObject *self, void *closure)
404 {
405         return PyString_FromString(channel_get_name(self->channel));
406 }
407
408 static int
409 Channel_set_name(ChannelObject *self, PyObject *value, void *closure)
410 {
411         channel_rename(self->channel, PyString_AsString(value));
412         return 0;
413 }
414
415 static PyObject*
416 Channel_get_balance_midi_cc(ChannelObject *self, void *closure)
417 {
418         return PyInt_FromLong(channel_get_balance_midi_cc(self->channel));
419 }
420
421 static int
422 Channel_set_balance_midi_cc(ChannelObject *self, PyObject *value, void *closure)
423 {
424         unsigned int new_cc;
425         unsigned int result;
426
427         new_cc = PyInt_AsLong(value);
428         result = channel_set_balance_midi_cc(self->channel, new_cc);
429         if (result == 0) {
430                 return 0;
431         }
432         if (result == 1) {
433                 PyErr_SetString(PyExc_RuntimeError, "value already in use");
434         } else if (result == 2) {
435                 PyErr_SetString(PyExc_RuntimeError, "value out of range");
436         }
437         return -1;
438 }
439
440 static PyObject*
441 Channel_get_volume_midi_cc(ChannelObject *self, void *closure)
442 {
443         return PyInt_FromLong(channel_get_volume_midi_cc(self->channel));
444 }
445
446 static int
447 Channel_set_volume_midi_cc(ChannelObject *self, PyObject *value, void *closure)
448 {
449         unsigned int new_cc;
450         unsigned int result;
451
452         new_cc = PyInt_AsLong(value);
453         result = channel_set_volume_midi_cc(self->channel, new_cc);
454         if (result == 0) {
455                 return 0;
456         }
457         if (result == 1) {
458                 PyErr_SetString(PyExc_RuntimeError, "value already in use");
459         } else if (result == 2) {
460                 PyErr_SetString(PyExc_RuntimeError, "value out of range");
461         }
462         return -1;
463 }
464
465 static PyObject*
466 Channel_get_midi_in_got_events(ChannelObject *self, void *closure)
467 {
468         PyObject *result;
469
470         if (channel_get_midi_in_got_events(self->channel)) {
471                 result = Py_True;
472         } else {
473                 result = Py_False;
474         }
475         Py_INCREF(result);
476         return result;
477 }
478
479
480 static PyGetSetDef Channel_getseters[] = {
481         {"is_stereo", 
482                 (getter)Channel_get_is_stereo, NULL,
483                 "mono/stereo", NULL},
484         {"volume", 
485                 (getter)Channel_get_volume, (setter)Channel_set_volume,
486                 "volume", NULL},
487         {"balance", 
488                 (getter)Channel_get_balance, (setter)Channel_set_balance,
489                 "balance", NULL},
490         {"mute", 
491                 (getter)Channel_get_mute, (setter)Channel_set_mute,
492                 "mute", NULL},
493         {"out_mute",
494                 (getter)Channel_get_out_mute, (setter)Channel_set_out_mute,
495                 "out_mute", NULL},
496         {"solo",
497                 (getter)Channel_get_solo, (setter)Channel_set_solo,
498                 "solo", NULL},
499         {"meter",
500                 (getter)Channel_get_meter, NULL,
501                 "meter", NULL},
502         {"abspeak", 
503                 (getter)Channel_get_abspeak, (setter)Channel_set_abspeak,
504                 "balance", NULL},
505         {"midi_scale",
506                 NULL, (setter)Channel_set_midi_scale,
507                 "midi scale", NULL},
508         {"midi_change_callback",
509                 (getter)Channel_get_midi_change_callback,
510                 (setter)Channel_set_midi_change_callback,
511                 "midi change callback", NULL},
512         {"name",
513                 (getter)Channel_get_name,
514                 (setter)Channel_set_name,
515                 "name", NULL},
516         {"balance_midi_cc",
517                 (getter)Channel_get_balance_midi_cc,
518                 (setter)Channel_set_balance_midi_cc,
519                 "Balance MIDI CC", NULL},
520         {"volume_midi_cc",
521                 (getter)Channel_get_volume_midi_cc,
522                 (setter)Channel_set_volume_midi_cc,
523                 "Volume MIDI CC", NULL},
524         {"midi_in_got_events",
525                 (getter)Channel_get_midi_in_got_events, NULL,
526                 "Got new MIDI IN events", NULL},
527         {NULL}
528 };
529
530 static PyObject*
531 Channel_remove(ChannelObject *self, PyObject *args)
532 {
533         if (! PyArg_ParseTuple(args, "")) return NULL;
534         remove_channel(self->channel);
535         Py_INCREF(Py_None);
536         return Py_None;
537 }
538
539 static PyObject*
540 Channel_autoset_midi_cc(ChannelObject *self, PyObject *args)
541 {
542         if (! PyArg_ParseTuple(args, "")) return NULL;
543         channel_autoset_midi_cc(self->channel);
544         Py_INCREF(Py_None);
545         return Py_None;
546 }
547
548 static PyMethodDef channel_methods[] = {
549         {"remove", (PyCFunction)Channel_remove, METH_VARARGS, "Remove"},
550         {"autoset_midi_cc", (PyCFunction)Channel_autoset_midi_cc, METH_VARARGS, "Autoset MIDI CC"},
551         {NULL}
552 };
553
554 static PyTypeObject ChannelType = {
555         PyObject_HEAD_INIT(NULL)
556         0,       /*ob_size*/
557         "jack_mixer_c.Channel",    /*tp_name*/
558         sizeof(ChannelObject), /*tp_basicsize*/
559         0,       /*tp_itemsize*/
560         (destructor)Channel_dealloc,       /*tp_dealloc*/
561         0,       /*tp_print*/
562         0,       /*tp_getattr*/
563         0,       /*tp_setattr*/
564         0,       /*tp_compare*/
565         0,       /*tp_repr*/
566         0,       /*tp_as_number*/
567         0,       /*tp_as_sequence*/
568         0,       /*tp_as_mapping*/
569         0,       /*tp_hash */
570         0,       /*tp_call*/
571         0,       /*tp_str*/
572         0,       /*tp_getattro*/
573         0,       /*tp_setattro*/
574         0,       /*tp_as_buffer*/
575         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
576         "Channel objects",           /* tp_doc */
577         0,                         /* tp_traverse */
578         0,                         /* tp_clear */
579         0,                         /* tp_richcompare */
580         0,                         /* tp_weaklistoffset */
581         0,                         /* tp_iter */
582         0,                         /* tp_iternext */
583         channel_methods,           /* tp_methods */
584         0,             /* tp_members */
585         Channel_getseters,           /* tp_getset */
586         0,                         /* tp_base */
587         0,                         /* tp_dict */
588         0,                         /* tp_descr_get */
589         0,                         /* tp_descr_set */
590         0,                         /* tp_dictoffset */
591         (initproc)Channel_init,    /* tp_init */
592         0,                         /* tp_alloc */
593         Channel_new,                 /* tp_new */
594 };
595
596 static PyObject*
597 Channel_New(jack_mixer_channel_t channel)
598 {
599         ChannelObject *self;
600         self = (ChannelObject*)PyObject_NEW(ChannelObject, &ChannelType);
601         if (self != NULL) {
602                 self->channel = channel;
603                 self->midi_change_callback = NULL;
604         }
605         return (PyObject*)self;
606 }
607
608 /** Output Channel Type **/
609
610 typedef struct {
611         PyObject_HEAD
612         PyObject *midi_change_callback;
613         jack_mixer_output_channel_t *output_channel;
614 } OutputChannelObject;
615
616 static int
617 OutputChannel_set_prefader(OutputChannelObject *self, PyObject *value, void *closure)
618 {
619         if (value == Py_True) {
620                 output_channel_set_prefader(self->output_channel, true);
621         } else {
622                 output_channel_set_prefader(self->output_channel, false);
623         }
624         return 0;
625 }
626
627 static PyObject*
628 OutputChannel_get_prefader(OutputChannelObject *self, void *closure)
629 {
630         PyObject *result;
631
632         if (output_channel_is_prefader(self->output_channel)) {
633                 result = Py_True;
634         } else {
635                 result = Py_False;
636         }
637         Py_INCREF(result);
638         return result;
639 }
640
641 static PyGetSetDef OutputChannel_getseters[] = {
642         {"prefader", 
643                 (getter)OutputChannel_get_prefader, (setter)OutputChannel_set_prefader,
644                 "prefader", NULL},
645         {NULL}
646 };
647
648 static PyObject*
649 OutputChannel_remove(OutputChannelObject *self, PyObject *args)
650 {
651         if (! PyArg_ParseTuple(args, "")) return NULL;
652         remove_output_channel(self->output_channel);
653         Py_INCREF(Py_None);
654         return Py_None;
655 }
656
657 static PyObject*
658 OutputChannel_set_solo(OutputChannelObject *self, PyObject *args)
659 {
660         PyObject *channel;
661         unsigned char solo;
662
663         if (! PyArg_ParseTuple(args, "Ob", &channel, &solo)) return NULL;
664
665         output_channel_set_solo(self->output_channel,
666                         ((ChannelObject*)channel)->channel,
667                         solo);
668
669         Py_INCREF(Py_None);
670         return Py_None;
671 }
672
673 static PyObject*
674 OutputChannel_set_muted(OutputChannelObject *self, PyObject *args)
675 {
676         PyObject *channel;
677         unsigned char muted;
678
679         if (! PyArg_ParseTuple(args, "Ob", &channel, &muted)) return NULL;
680
681         output_channel_set_muted(self->output_channel,
682                         ((ChannelObject*)channel)->channel,
683                         muted);
684
685         Py_INCREF(Py_None);
686         return Py_None;
687 }
688
689 static PyObject*
690 OutputChannel_is_solo(OutputChannelObject *self, PyObject *args)
691 {
692         PyObject *channel;
693         PyObject *result;
694
695         if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
696
697         if (output_channel_is_solo(self->output_channel,
698                         ((ChannelObject*)channel)->channel)) {
699                 result = Py_True;
700         } else {
701                 result = Py_False;
702         }
703
704         Py_INCREF(result);
705         return result;
706 }
707
708 static PyObject*
709 OutputChannel_is_muted(OutputChannelObject *self, PyObject *args)
710 {
711         PyObject *channel;
712         PyObject *result;
713
714         if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
715
716         if (output_channel_is_muted(self->output_channel,
717                         ((ChannelObject*)channel)->channel)) {
718                 result = Py_True;
719         } else {
720                 result = Py_False;
721         }
722
723         Py_INCREF(result);
724         return result;
725 }
726
727 static PyMethodDef output_channel_methods[] = {
728         {"remove", (PyCFunction)OutputChannel_remove, METH_VARARGS, "Remove"},
729         {"set_solo", (PyCFunction)OutputChannel_set_solo, METH_VARARGS, "Set a channel as solo"},
730         {"set_muted", (PyCFunction)OutputChannel_set_muted, METH_VARARGS, "Set a channel as muted"},
731         {"is_solo", (PyCFunction)OutputChannel_is_solo, METH_VARARGS, "Is a channel set as solo"},
732         {"is_muted", (PyCFunction)OutputChannel_is_muted, METH_VARARGS, "Is a channel set as muted"},
733         {NULL}
734 };
735
736 static PyTypeObject OutputChannelType = {
737         PyObject_HEAD_INIT(NULL)
738         0,       /*ob_size*/
739         "jack_mixer_c.OutputChannel",    /*tp_name*/
740         sizeof(OutputChannelObject), /*tp_basicsize*/
741         0,       /*tp_itemsize*/
742         0,       /*tp_dealloc*/
743         0,       /*tp_print*/
744         0,       /*tp_getattr*/
745         0,       /*tp_setattr*/
746         0,       /*tp_compare*/
747         0,       /*tp_repr*/
748         0,       /*tp_as_number*/
749         0,       /*tp_as_sequence*/
750         0,       /*tp_as_mapping*/
751         0,       /*tp_hash */
752         0,       /*tp_call*/
753         0,       /*tp_str*/
754         0,       /*tp_getattro*/
755         0,       /*tp_setattro*/
756         0,       /*tp_as_buffer*/
757         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
758         "Output Channel objects",           /* tp_doc */
759         0,                         /* tp_traverse */
760         0,                         /* tp_clear */
761         0,                         /* tp_richcompare */
762         0,                         /* tp_weaklistoffset */
763         0,                         /* tp_iter */
764         0,                         /* tp_iternext */
765         output_channel_methods,    /* tp_methods */
766         0,             /* tp_members */
767         OutputChannel_getseters,   /* tp_getset */
768         &ChannelType,              /* tp_base */
769         0,                         /* tp_dict */
770         0,                         /* tp_descr_get */
771         0,                         /* tp_descr_set */
772         0,                         /* tp_dictoffset */
773         0,                         /* tp_init */
774         0,                         /* tp_alloc */
775         0,                         /* tp_new */
776 };
777
778 static PyObject*
779 OutputChannel_New(jack_mixer_output_channel_t output_channel)
780 {
781         OutputChannelObject *self;
782         self = (OutputChannelObject*)PyObject_NEW(OutputChannelObject, &OutputChannelType);
783         if (self != NULL) {
784                 self->midi_change_callback = NULL;
785                 self->output_channel = output_channel;
786         }
787         return (PyObject*)self;
788 }
789
790
791 /** Mixer Type **/
792
793 typedef struct {
794         PyObject_HEAD
795         PyObject *main_mix_channel;
796         jack_mixer_t mixer;
797 } MixerObject;
798
799 static void
800 Mixer_dealloc(MixerObject *self)
801 {
802         Py_XDECREF(self->main_mix_channel);
803         if (self->mixer)
804                 destroy(self->mixer);
805         self->ob_type->tp_free((PyObject*)self);
806 }
807
808 static PyObject*
809 Mixer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
810 {
811         MixerObject *self;
812
813         self = (MixerObject*)type->tp_alloc(type, 0);
814
815         if (self != NULL) {
816                 self->main_mix_channel = NULL;
817                 self->mixer = NULL;
818         }
819
820         return (PyObject*)self;
821 }
822
823 static int
824 Mixer_init(MixerObject *self, PyObject *args, PyObject *kwds)
825 {
826         static char *kwlist[] = {"name", "stereo", NULL};
827         char *name;
828         int stereo = 1;
829
830         if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|b", kwlist, &name, &stereo))
831                 return -1;
832         
833         self->mixer = create(name, (bool)stereo);
834         if (self->mixer == NULL) {
835                 PyErr_SetString(PyExc_RuntimeError,
836                                 "error creating mixer, probably jack is not running");
837                 return -1;
838         }
839
840         self->main_mix_channel = Channel_New(get_main_mix_channel(self->mixer));
841
842         return 0;
843 }
844
845 static PyMemberDef Mixer_members[] = {
846         {"main_mix_channel", T_OBJECT, offsetof(MixerObject, main_mix_channel), 0, "main_mix_channel"},
847         {NULL}
848 };
849
850 static PyObject*
851 Mixer_get_channels_count(MixerObject *self, void *closure)
852 {
853         return PyInt_FromLong(get_channels_count(self->mixer));
854 }
855
856 static PyObject*
857 Mixer_get_client_name(MixerObject *self, void *closure)
858 {
859         return PyString_FromString(get_client_name(self->mixer));
860 }
861
862 static PyObject*
863 Mixer_get_last_midi_channel(MixerObject *self, void *closure)
864 {
865         return PyInt_FromLong(get_last_midi_channel(self->mixer));
866 }
867
868
869 static PyGetSetDef Mixer_getseters[] = {
870         {"channels_count", (getter)Mixer_get_channels_count, NULL,
871                 "channels count", NULL},
872         {"last_midi_channel", (getter)Mixer_get_last_midi_channel, NULL,
873                 "last midi channel", NULL},
874         {NULL}
875 };
876
877 static PyObject*
878 Mixer_add_channel(MixerObject *self, PyObject *args)
879 {
880         char *name;
881         int stereo;
882         jack_mixer_channel_t channel;
883
884         if (! PyArg_ParseTuple(args, "si", &name, &stereo)) return NULL;
885
886         channel = add_channel(self->mixer, name, (bool)stereo);
887
888         if (channel == NULL) {
889                 PyErr_SetString(PyExc_RuntimeError, "error adding channel");
890                 return NULL;
891         }
892
893         return Channel_New(channel);
894 }
895
896 static PyObject*
897 Mixer_add_output_channel(MixerObject *self, PyObject *args)
898 {
899         char *name;
900         int stereo = 1;
901         int system = 0;
902         jack_mixer_output_channel_t channel;
903
904         if (! PyArg_ParseTuple(args, "s|bb", &name, &stereo, &system)) return NULL;
905
906         channel = add_output_channel(self->mixer, name, (bool)stereo, (bool)system);
907
908         return OutputChannel_New(channel);
909 }
910
911 static PyObject*
912 Mixer_destroy(MixerObject *self, PyObject *args)
913 {
914         if (self->mixer) {
915                 destroy(self->mixer);
916                 self->mixer = NULL;
917         }
918         Py_INCREF(Py_None);
919         return Py_None;
920 }
921
922 static PyMethodDef Mixer_methods[] = {
923         {"add_channel", (PyCFunction)Mixer_add_channel, METH_VARARGS, "Add a new channel"},
924         {"add_output_channel", (PyCFunction)Mixer_add_output_channel, METH_VARARGS, "Add a new output channel"},
925         {"destroy", (PyCFunction)Mixer_destroy, METH_VARARGS, "Destroy JACK Mixer"},
926         {"client_name", (PyCFunction)Mixer_get_client_name, METH_VARARGS, "Get jack client name"},
927 //      {"remove_channel", (PyCFunction)Mixer_remove_channel, METH_VARARGS, "Remove a channel"},
928         {NULL}
929 };
930
931 static PyTypeObject MixerType = {
932         PyObject_HEAD_INIT(NULL)
933         0,       /*ob_size*/
934         "jack_mixer_c.Mixer",    /*tp_name*/
935         sizeof(MixerObject), /*tp_basicsize*/
936         0,       /*tp_itemsize*/
937         (destructor)Mixer_dealloc,       /*tp_dealloc*/
938         0,       /*tp_print*/
939         0,       /*tp_getattr*/
940         0,       /*tp_setattr*/
941         0,       /*tp_compare*/
942         0,       /*tp_repr*/
943         0,       /*tp_as_number*/
944         0,       /*tp_as_sequence*/
945         0,       /*tp_as_mapping*/
946         0,       /*tp_hash */
947         0,       /*tp_call*/
948         0,       /*tp_str*/
949         0,       /*tp_getattro*/
950         0,       /*tp_setattro*/
951         0,       /*tp_as_buffer*/
952         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
953         "Mixer objects",           /* tp_doc */
954         0,                         /* tp_traverse */
955         0,                         /* tp_clear */
956         0,                         /* tp_richcompare */
957         0,                         /* tp_weaklistoffset */
958         0,                         /* tp_iter */
959         0,                         /* tp_iternext */
960         Mixer_methods,             /* tp_methods */
961         Mixer_members,             /* tp_members */
962         Mixer_getseters,           /* tp_getset */
963         0,                         /* tp_base */
964         0,                         /* tp_dict */
965         0,                         /* tp_descr_get */
966         0,                         /* tp_descr_set */
967         0,                         /* tp_dictoffset */
968         (initproc)Mixer_init,      /* tp_init */
969         0,                         /* tp_alloc */
970         Mixer_new,                 /* tp_new */
971 };
972
973
974 static PyMethodDef jack_mixer_methods[] = {
975         {NULL}  /* Sentinel */
976 };
977
978
979
980 PyMODINIT_FUNC initjack_mixer_c(void)
981 {
982         PyObject *m;
983
984         if (PyType_Ready(&MixerType) < 0)
985                 return;
986         if (PyType_Ready(&ChannelType) < 0)
987                 return;
988         if (PyType_Ready(&OutputChannelType) < 0)
989                 return;
990         if (PyType_Ready(&ScaleType) < 0)
991                 return;
992         
993         m = Py_InitModule3("jack_mixer_c", jack_mixer_methods, "Jack Mixer C Helper Module");
994
995         Py_INCREF(&MixerType);
996         PyModule_AddObject(m, "Mixer", (PyObject*)&MixerType);
997         Py_INCREF(&ChannelType);
998         PyModule_AddObject(m, "Channel", (PyObject*)&ChannelType);
999         Py_INCREF(&OutputChannelType);
1000         PyModule_AddObject(m, "OutputChannel", (PyObject*)&OutputChannelType);
1001         Py_INCREF(&ScaleType);
1002         PyModule_AddObject(m, "Scale", (PyObject*)&ScaleType);
1003 }
1004