]> git.0d.be Git - jack_mixer.git/blob - jack_mixer_c.c
Add methods to know if a channel has been muted/soloed
[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         channel_volume_write(self->channel, PyFloat_AsDouble(value));
215         return 0;
216 }
217
218 static PyObject*
219 Channel_get_balance(ChannelObject *self, void *closure)
220 {
221         return PyFloat_FromDouble(channel_balance_read(self->channel));
222 }
223
224 static int
225 Channel_set_balance(ChannelObject *self, PyObject *value, void *closure)
226 {
227         channel_balance_write(self->channel, PyFloat_AsDouble(value));
228         return 0;
229 }
230
231 static PyObject*
232 Channel_get_mute(ChannelObject *self, void *closure)
233 {
234         PyObject *result;
235
236         if (channel_is_muted(self->channel)) {
237                 result = Py_True;
238         } else {
239                 result = Py_False;
240         }
241         Py_INCREF(result);
242         return result;
243 }
244
245 static int
246 Channel_set_mute(ChannelObject *self, PyObject *value, void *closure)
247 {
248         if (value == Py_True) {
249                 channel_mute(self->channel);
250         } else {
251                 channel_unmute(self->channel);
252         }
253         return 0;
254 }
255
256 static PyObject*
257 Channel_get_solo(ChannelObject *self, void *closure)
258 {
259         PyObject *result;
260
261         if (channel_is_soloed(self->channel)) {
262                 result = Py_True;
263         } else {
264                 result = Py_False;
265         }
266         Py_INCREF(result);
267         return result;
268 }
269
270 static int
271 Channel_set_solo(ChannelObject *self, PyObject *value, void *closure)
272 {
273         if (value == Py_True) {
274                 channel_solo(self->channel);
275         } else {
276                 channel_unsolo(self->channel);
277         }
278         return 0;
279 }
280
281 static PyObject*
282 Channel_get_meter(ChannelObject *self, void *closure)
283 {
284         PyObject *result;
285         double left, right;
286
287         if (channel_is_stereo(self->channel)) {
288                 result = PyTuple_New(2);
289                 channel_stereo_meter_read(self->channel, &left, &right);
290                 PyTuple_SetItem(result, 0, PyFloat_FromDouble(left));
291                 PyTuple_SetItem(result, 1, PyFloat_FromDouble(right));
292         } else {
293                 result = PyTuple_New(1);
294                 channel_mono_meter_read(self->channel, &left);
295                 PyTuple_SetItem(result, 0, PyFloat_FromDouble(left));
296         }
297         return result;
298 }
299
300 static PyObject*
301 Channel_get_abspeak(ChannelObject *self, void *closure)
302 {
303         return PyFloat_FromDouble(channel_abspeak_read(self->channel));
304 }
305
306 static int
307 Channel_set_abspeak(ChannelObject *self, PyObject *value, void *closure)
308 {
309         if (value != Py_None) {
310                 fprintf(stderr, "abspeak can only be reset (set to None)\n");
311                 return -1;
312         }
313         channel_abspeak_reset(self->channel);
314         return 0;
315 }
316
317 static int
318 Channel_set_midi_scale(ChannelObject *self, PyObject *value, void *closure)
319 {
320         ScaleObject *scale_object = (ScaleObject*)value; /* XXX: check */
321
322         channel_set_midi_scale(self->channel, scale_object->scale);
323         return 0;
324 }
325
326
327 static PyObject*
328 Channel_get_midi_change_callback(ChannelObject *self, void *closure)
329 {
330         if (self->midi_change_callback) {
331                 Py_INCREF(self->midi_change_callback);
332                 return self->midi_change_callback;
333         } else {
334                 Py_INCREF(Py_None);
335                 return Py_None;
336         }
337 }
338
339 static void
340 channel_midi_callback(void *userdata)
341 {
342         ChannelObject *self = (ChannelObject*)userdata;
343         PyGILState_STATE gstate;
344
345         gstate = PyGILState_Ensure();
346         PyObject_CallObject(self->midi_change_callback, NULL);
347         PyGILState_Release(gstate);
348 }
349
350 static int
351 Channel_set_midi_change_callback(ChannelObject *self, PyObject *value, void *closure)
352 {
353         if (value == Py_None) {
354                 self->midi_change_callback = NULL;
355                 channel_set_midi_change_callback(self->channel, NULL, NULL);
356         } else {
357                 if (!PyCallable_Check(value)) {
358                         PyErr_SetString(PyExc_TypeError, "value must be callable");
359                         return -1;
360                 }
361                 if (self->midi_change_callback) {
362                         Py_XDECREF(self->midi_change_callback);
363                 }
364                 Py_INCREF(value);
365                 self->midi_change_callback = value;
366                 channel_set_midi_change_callback(self->channel,
367                                 channel_midi_callback, self);
368         }
369
370         return 0;
371 }
372
373 static PyObject*
374 Channel_get_name(ChannelObject *self, void *closure)
375 {
376         return PyString_FromString(channel_get_name(self->channel));
377 }
378
379 static int
380 Channel_set_name(ChannelObject *self, PyObject *value, void *closure)
381 {
382         channel_rename(self->channel, PyString_AsString(value));
383         return 0;
384 }
385
386 static PyObject*
387 Channel_get_balance_midi_cc(ChannelObject *self, void *closure)
388 {
389         return PyInt_FromLong(channel_get_balance_midi_cc(self->channel));
390 }
391
392 static int
393 Channel_set_balance_midi_cc(ChannelObject *self, PyObject *value, void *closure)
394 {
395         unsigned int new_cc;
396         unsigned int result;
397
398         new_cc = PyInt_AsLong(value);
399         result = channel_set_balance_midi_cc(self->channel, new_cc);
400         if (result == 0) {
401                 return 0;
402         }
403         if (result == 1) {
404                 PyErr_SetString(PyExc_RuntimeError, "value already in use");
405         } else if (result == 2) {
406                 PyErr_SetString(PyExc_RuntimeError, "value out of range");
407         }
408         return -1;
409 }
410
411 static PyObject*
412 Channel_get_volume_midi_cc(ChannelObject *self, void *closure)
413 {
414         return PyInt_FromLong(channel_get_volume_midi_cc(self->channel));
415 }
416
417 static int
418 Channel_set_volume_midi_cc(ChannelObject *self, PyObject *value, void *closure)
419 {
420         unsigned int new_cc;
421         unsigned int result;
422
423         new_cc = PyInt_AsLong(value);
424         result = channel_set_volume_midi_cc(self->channel, new_cc);
425         if (result == 0) {
426                 return 0;
427         }
428         if (result == 1) {
429                 PyErr_SetString(PyExc_RuntimeError, "value already in use");
430         } else if (result == 2) {
431                 PyErr_SetString(PyExc_RuntimeError, "value out of range");
432         }
433         return -1;
434 }
435
436 static PyGetSetDef Channel_getseters[] = {
437         {"is_stereo", 
438                 (getter)Channel_get_is_stereo, NULL,
439                 "mono/stereo", NULL},
440         {"volume", 
441                 (getter)Channel_get_volume, (setter)Channel_set_volume,
442                 "volume", NULL},
443         {"balance", 
444                 (getter)Channel_get_balance, (setter)Channel_set_balance,
445                 "balance", NULL},
446         {"mute", 
447                 (getter)Channel_get_mute, (setter)Channel_set_mute,
448                 "mute", NULL},
449         {"solo", 
450                 (getter)Channel_get_solo, (setter)Channel_set_solo,
451                 "solo", NULL},
452         {"meter",
453                 (getter)Channel_get_meter, NULL,
454                 "meter", NULL},
455         {"abspeak", 
456                 (getter)Channel_get_abspeak, (setter)Channel_set_abspeak,
457                 "balance", NULL},
458         {"midi_scale",
459                 NULL, (setter)Channel_set_midi_scale,
460                 "midi scale", NULL},
461         {"midi_change_callback",
462                 (getter)Channel_get_midi_change_callback,
463                 (setter)Channel_set_midi_change_callback,
464                 "midi change callback", NULL},
465         {"name",
466                 (getter)Channel_get_name,
467                 (setter)Channel_set_name,
468                 "name", NULL},
469         {"balance_midi_cc",
470                 (getter)Channel_get_balance_midi_cc,
471                 (setter)Channel_set_balance_midi_cc,
472                 "Balance MIDI CC", NULL},
473         {"volume_midi_cc",
474                 (getter)Channel_get_volume_midi_cc,
475                 (setter)Channel_set_volume_midi_cc,
476                 "Volume MIDI CC", NULL},
477         {NULL}
478 };
479
480 static PyObject*
481 Channel_remove(ChannelObject *self, PyObject *args)
482 {
483         if (! PyArg_ParseTuple(args, "")) return NULL;
484         remove_channel(self->channel);
485         Py_INCREF(Py_None);
486         return Py_None;
487 }
488
489 static PyObject*
490 Channel_autoset_midi_cc(ChannelObject *self, PyObject *args)
491 {
492         if (! PyArg_ParseTuple(args, "")) return NULL;
493         channel_autoset_midi_cc(self->channel);
494         Py_INCREF(Py_None);
495         return Py_None;
496 }
497
498 static PyMethodDef channel_methods[] = {
499         {"remove", (PyCFunction)Channel_remove, METH_VARARGS, "Remove"},
500         {"autoset_midi_cc", (PyCFunction)Channel_autoset_midi_cc, METH_VARARGS, "Autoset MIDI CC"},
501         {NULL}
502 };
503
504 static PyTypeObject ChannelType = {
505         PyObject_HEAD_INIT(NULL)
506         0,       /*ob_size*/
507         "jack_mixer_c.Channel",    /*tp_name*/
508         sizeof(ChannelObject), /*tp_basicsize*/
509         0,       /*tp_itemsize*/
510         (destructor)Channel_dealloc,       /*tp_dealloc*/
511         0,       /*tp_print*/
512         0,       /*tp_getattr*/
513         0,       /*tp_setattr*/
514         0,       /*tp_compare*/
515         0,       /*tp_repr*/
516         0,       /*tp_as_number*/
517         0,       /*tp_as_sequence*/
518         0,       /*tp_as_mapping*/
519         0,       /*tp_hash */
520         0,       /*tp_call*/
521         0,       /*tp_str*/
522         0,       /*tp_getattro*/
523         0,       /*tp_setattro*/
524         0,       /*tp_as_buffer*/
525         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
526         "Channel objects",           /* tp_doc */
527         0,                         /* tp_traverse */
528         0,                         /* tp_clear */
529         0,                         /* tp_richcompare */
530         0,                         /* tp_weaklistoffset */
531         0,                         /* tp_iter */
532         0,                         /* tp_iternext */
533         channel_methods,           /* tp_methods */
534         0,             /* tp_members */
535         Channel_getseters,           /* tp_getset */
536         0,                         /* tp_base */
537         0,                         /* tp_dict */
538         0,                         /* tp_descr_get */
539         0,                         /* tp_descr_set */
540         0,                         /* tp_dictoffset */
541         (initproc)Channel_init,    /* tp_init */
542         0,                         /* tp_alloc */
543         Channel_new,                 /* tp_new */
544 };
545
546 static PyObject*
547 Channel_New(jack_mixer_channel_t channel)
548 {
549         ChannelObject *self;
550         self = (ChannelObject*)PyObject_NEW(ChannelObject, &ChannelType);
551         if (self != NULL) {
552                 self->channel = channel;
553                 self->midi_change_callback = NULL;
554         }
555         return (PyObject*)self;
556 }
557
558 /** Output Channel Type **/
559
560 typedef struct {
561         PyObject_HEAD
562         PyObject *midi_change_callback;
563         jack_mixer_output_channel_t *output_channel;
564 } OutputChannelObject;
565
566 static PyObject*
567 OutputChannel_remove(OutputChannelObject *self, PyObject *args)
568 {
569         if (! PyArg_ParseTuple(args, "")) return NULL;
570         remove_output_channel(self->output_channel);
571         Py_INCREF(Py_None);
572         return Py_None;
573 }
574
575 static PyObject*
576 OutputChannel_set_solo(OutputChannelObject *self, PyObject *args)
577 {
578         PyObject *channel;
579         unsigned char solo;
580
581         if (! PyArg_ParseTuple(args, "Ob", &channel, &solo)) return NULL;
582
583         output_channel_set_solo(self->output_channel,
584                         ((ChannelObject*)channel)->channel,
585                         solo);
586
587         Py_INCREF(Py_None);
588         return Py_None;
589 }
590
591 static PyObject*
592 OutputChannel_set_muted(OutputChannelObject *self, PyObject *args)
593 {
594         PyObject *channel;
595         unsigned char muted;
596
597         if (! PyArg_ParseTuple(args, "Ob", &channel, &muted)) return NULL;
598
599         output_channel_set_muted(self->output_channel,
600                         ((ChannelObject*)channel)->channel,
601                         muted);
602
603         Py_INCREF(Py_None);
604         return Py_None;
605 }
606
607 static PyObject*
608 OutputChannel_is_solo(OutputChannelObject *self, PyObject *args)
609 {
610         PyObject *channel;
611         PyObject *result;
612
613         if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
614
615         if (output_channel_is_solo(self->output_channel,
616                         ((ChannelObject*)channel)->channel)) {
617                 result = Py_True;
618         } else {
619                 result = Py_False;
620         }
621
622         Py_INCREF(result);
623         return result;
624 }
625
626 static PyObject*
627 OutputChannel_is_muted(OutputChannelObject *self, PyObject *args)
628 {
629         PyObject *channel;
630         PyObject *result;
631
632         if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
633
634         if (output_channel_is_muted(self->output_channel,
635                         ((ChannelObject*)channel)->channel)) {
636                 result = Py_True;
637         } else {
638                 result = Py_False;
639         }
640
641         Py_INCREF(result);
642         return result;
643 }
644
645 static PyMethodDef output_channel_methods[] = {
646         {"remove", (PyCFunction)OutputChannel_remove, METH_VARARGS, "Remove"},
647         {"set_solo", (PyCFunction)OutputChannel_set_solo, METH_VARARGS, "Set a channel as solo"},
648         {"set_muted", (PyCFunction)OutputChannel_set_muted, METH_VARARGS, "Set a channel as muted"},
649         {"is_solo", (PyCFunction)OutputChannel_is_solo, METH_VARARGS, "Is a channel set as solo"},
650         {"is_muted", (PyCFunction)OutputChannel_is_muted, METH_VARARGS, "Is a channel set as muted"},
651         {NULL}
652 };
653
654 static PyTypeObject OutputChannelType = {
655         PyObject_HEAD_INIT(NULL)
656         0,       /*ob_size*/
657         "jack_mixer_c.OutputChannel",    /*tp_name*/
658         sizeof(OutputChannelObject), /*tp_basicsize*/
659         0,       /*tp_itemsize*/
660         0,       /*tp_dealloc*/
661         0,       /*tp_print*/
662         0,       /*tp_getattr*/
663         0,       /*tp_setattr*/
664         0,       /*tp_compare*/
665         0,       /*tp_repr*/
666         0,       /*tp_as_number*/
667         0,       /*tp_as_sequence*/
668         0,       /*tp_as_mapping*/
669         0,       /*tp_hash */
670         0,       /*tp_call*/
671         0,       /*tp_str*/
672         0,       /*tp_getattro*/
673         0,       /*tp_setattro*/
674         0,       /*tp_as_buffer*/
675         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
676         "Output Channel objects",           /* tp_doc */
677         0,                         /* tp_traverse */
678         0,                         /* tp_clear */
679         0,                         /* tp_richcompare */
680         0,                         /* tp_weaklistoffset */
681         0,                         /* tp_iter */
682         0,                         /* tp_iternext */
683         output_channel_methods,    /* tp_methods */
684         0,             /* tp_members */
685         0,           /* tp_getset */
686         &ChannelType,              /* tp_base */
687         0,                         /* tp_dict */
688         0,                         /* tp_descr_get */
689         0,                         /* tp_descr_set */
690         0,                         /* tp_dictoffset */
691         0,                         /* tp_init */
692         0,                         /* tp_alloc */
693         0,                         /* tp_new */
694 };
695
696 static PyObject*
697 OutputChannel_New(jack_mixer_output_channel_t output_channel)
698 {
699         OutputChannelObject *self;
700         self = (OutputChannelObject*)PyObject_NEW(OutputChannelObject, &OutputChannelType);
701         if (self != NULL) {
702                 self->midi_change_callback = NULL;
703                 self->output_channel = output_channel;
704         }
705         return (PyObject*)self;
706 }
707
708
709 /** Mixer Type **/
710
711 typedef struct {
712         PyObject_HEAD
713         PyObject *main_mix_channel;
714         jack_mixer_t mixer;
715 } MixerObject;
716
717 static void
718 Mixer_dealloc(MixerObject *self)
719 {
720         Py_XDECREF(self->main_mix_channel);
721         if (self->mixer)
722                 destroy(self->mixer);
723         self->ob_type->tp_free((PyObject*)self);
724 }
725
726 static PyObject*
727 Mixer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
728 {
729         MixerObject *self;
730
731         self = (MixerObject*)type->tp_alloc(type, 0);
732
733         if (self != NULL) {
734                 self->main_mix_channel = NULL;
735                 self->mixer = NULL;
736         }
737
738         return (PyObject*)self;
739 }
740
741 static int
742 Mixer_init(MixerObject *self, PyObject *args, PyObject *kwds)
743 {
744         static char *kwlist[] = {"name", NULL};
745         char *name;
746
747         if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &name))
748                 return -1;
749         
750         self->mixer = create(name);
751         if (self->mixer == NULL) {
752                 PyErr_SetString(PyExc_RuntimeError,
753                                 "error creating mixer, probably jack is not running");
754                 return -1;
755         }
756
757         self->main_mix_channel = Channel_New(get_main_mix_channel(self->mixer));
758
759         return 0;
760 }
761
762 static PyMemberDef Mixer_members[] = {
763         {"main_mix_channel", T_OBJECT, offsetof(MixerObject, main_mix_channel), 0, "main_mix_channel"},
764         {NULL}
765 };
766
767 static PyObject*
768 Mixer_get_channels_count(MixerObject *self, void *closure)
769 {
770         return PyInt_FromLong(get_channels_count(self->mixer));
771 }
772
773 static PyObject*
774 Mixer_get_last_midi_channel(MixerObject *self, void *closure)
775 {
776         return PyInt_FromLong(get_last_midi_channel(self->mixer));
777 }
778
779
780 static PyGetSetDef Mixer_getseters[] = {
781         {"channels_count", (getter)Mixer_get_channels_count, NULL,
782                 "channels count", NULL},
783         {"last_midi_channel", (getter)Mixer_get_last_midi_channel, NULL,
784                 "last midi channel", NULL},
785         {NULL}
786 };
787
788 static PyObject*
789 Mixer_add_channel(MixerObject *self, PyObject *args)
790 {
791         char *name;
792         int stereo;
793         jack_mixer_channel_t channel;
794
795         if (! PyArg_ParseTuple(args, "sb", &name, &stereo)) return NULL;
796
797         channel = add_channel(self->mixer, name, (bool)stereo);
798
799         if (channel == NULL) {
800                 PyErr_SetString(PyExc_RuntimeError, "error adding channel");
801                 return NULL;
802         }
803
804         return Channel_New(channel);
805 }
806
807 static PyObject*
808 Mixer_add_output_channel(MixerObject *self, PyObject *args)
809 {
810         char *name;
811         int stereo = 1;
812         int system = 0;
813         jack_mixer_output_channel_t channel;
814
815         if (! PyArg_ParseTuple(args, "s|bb", &name, &stereo, &system)) return NULL;
816
817         channel = add_output_channel(self->mixer, name, (bool)stereo, (bool)system);
818
819         return OutputChannel_New(channel);
820 }
821
822
823 static PyMethodDef Mixer_methods[] = {
824         {"add_channel", (PyCFunction)Mixer_add_channel, METH_VARARGS, "Add a new channel"},
825         {"add_output_channel", (PyCFunction)Mixer_add_output_channel, METH_VARARGS, "Add a new output channel"},
826 //      {"remove_channel", (PyCFunction)Mixer_remove_channel, METH_VARARGS, "Remove a channel"},
827         {NULL}
828 };
829
830 static PyTypeObject MixerType = {
831         PyObject_HEAD_INIT(NULL)
832         0,       /*ob_size*/
833         "jack_mixer_c.Mixer",    /*tp_name*/
834         sizeof(MixerObject), /*tp_basicsize*/
835         0,       /*tp_itemsize*/
836         (destructor)Mixer_dealloc,       /*tp_dealloc*/
837         0,       /*tp_print*/
838         0,       /*tp_getattr*/
839         0,       /*tp_setattr*/
840         0,       /*tp_compare*/
841         0,       /*tp_repr*/
842         0,       /*tp_as_number*/
843         0,       /*tp_as_sequence*/
844         0,       /*tp_as_mapping*/
845         0,       /*tp_hash */
846         0,       /*tp_call*/
847         0,       /*tp_str*/
848         0,       /*tp_getattro*/
849         0,       /*tp_setattro*/
850         0,       /*tp_as_buffer*/
851         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
852         "Mixer objects",           /* tp_doc */
853         0,                         /* tp_traverse */
854         0,                         /* tp_clear */
855         0,                         /* tp_richcompare */
856         0,                         /* tp_weaklistoffset */
857         0,                         /* tp_iter */
858         0,                         /* tp_iternext */
859         Mixer_methods,             /* tp_methods */
860         Mixer_members,             /* tp_members */
861         Mixer_getseters,           /* tp_getset */
862         0,                         /* tp_base */
863         0,                         /* tp_dict */
864         0,                         /* tp_descr_get */
865         0,                         /* tp_descr_set */
866         0,                         /* tp_dictoffset */
867         (initproc)Mixer_init,      /* tp_init */
868         0,                         /* tp_alloc */
869         Mixer_new,                 /* tp_new */
870 };
871
872
873 static PyMethodDef jack_mixer_methods[] = {
874         {NULL}  /* Sentinel */
875 };
876
877
878
879 PyMODINIT_FUNC initjack_mixer_c(void)
880 {
881         PyObject *m;
882
883         if (PyType_Ready(&MixerType) < 0)
884                 return;
885         if (PyType_Ready(&ChannelType) < 0)
886                 return;
887         if (PyType_Ready(&OutputChannelType) < 0)
888                 return;
889         if (PyType_Ready(&ScaleType) < 0)
890                 return;
891         
892         m = Py_InitModule3("jack_mixer_c", jack_mixer_methods, "Jack Mixer C Helper Module");
893
894         Py_INCREF(&MixerType);
895         PyModule_AddObject(m, "Mixer", (PyObject*)&MixerType);
896         Py_INCREF(&ChannelType);
897         PyModule_AddObject(m, "Channel", (PyObject*)&ChannelType);
898         Py_INCREF(&OutputChannelType);
899         PyModule_AddObject(m, "OutputChannel", (PyObject*)&OutputChannelType);
900         Py_INCREF(&ScaleType);
901         PyModule_AddObject(m, "Scale", (PyObject*)&ScaleType);
902 }
903