]> git.0d.be Git - jack_mixer.git/blob - jack_mixer_c.c
Renamed classes to conform to standard Python coding style (PEP-8)
[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 int
567 OutputChannel_set_prefader(OutputChannelObject *self, PyObject *value, void *closure)
568 {
569         if (value == Py_True) {
570                 output_channel_set_prefader(self->output_channel, true);
571         } else {
572                 output_channel_set_prefader(self->output_channel, false);
573         }
574         return 0;
575 }
576
577 static PyObject*
578 OutputChannel_get_prefader(OutputChannelObject *self, void *closure)
579 {
580         PyObject *result;
581
582         if (output_channel_is_prefader(self->output_channel)) {
583                 result = Py_True;
584         } else {
585                 result = Py_False;
586         }
587         Py_INCREF(result);
588         return result;
589 }
590
591 static PyGetSetDef OutputChannel_getseters[] = {
592         {"prefader", 
593                 (getter)OutputChannel_get_prefader, (setter)OutputChannel_set_prefader,
594                 "prefader", NULL},
595         {NULL}
596 };
597
598 static PyObject*
599 OutputChannel_remove(OutputChannelObject *self, PyObject *args)
600 {
601         if (! PyArg_ParseTuple(args, "")) return NULL;
602         remove_output_channel(self->output_channel);
603         Py_INCREF(Py_None);
604         return Py_None;
605 }
606
607 static PyObject*
608 OutputChannel_set_solo(OutputChannelObject *self, PyObject *args)
609 {
610         PyObject *channel;
611         unsigned char solo;
612
613         if (! PyArg_ParseTuple(args, "Ob", &channel, &solo)) return NULL;
614
615         output_channel_set_solo(self->output_channel,
616                         ((ChannelObject*)channel)->channel,
617                         solo);
618
619         Py_INCREF(Py_None);
620         return Py_None;
621 }
622
623 static PyObject*
624 OutputChannel_set_muted(OutputChannelObject *self, PyObject *args)
625 {
626         PyObject *channel;
627         unsigned char muted;
628
629         if (! PyArg_ParseTuple(args, "Ob", &channel, &muted)) return NULL;
630
631         output_channel_set_muted(self->output_channel,
632                         ((ChannelObject*)channel)->channel,
633                         muted);
634
635         Py_INCREF(Py_None);
636         return Py_None;
637 }
638
639 static PyObject*
640 OutputChannel_is_solo(OutputChannelObject *self, PyObject *args)
641 {
642         PyObject *channel;
643         PyObject *result;
644
645         if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
646
647         if (output_channel_is_solo(self->output_channel,
648                         ((ChannelObject*)channel)->channel)) {
649                 result = Py_True;
650         } else {
651                 result = Py_False;
652         }
653
654         Py_INCREF(result);
655         return result;
656 }
657
658 static PyObject*
659 OutputChannel_is_muted(OutputChannelObject *self, PyObject *args)
660 {
661         PyObject *channel;
662         PyObject *result;
663
664         if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
665
666         if (output_channel_is_muted(self->output_channel,
667                         ((ChannelObject*)channel)->channel)) {
668                 result = Py_True;
669         } else {
670                 result = Py_False;
671         }
672
673         Py_INCREF(result);
674         return result;
675 }
676
677 static PyMethodDef output_channel_methods[] = {
678         {"remove", (PyCFunction)OutputChannel_remove, METH_VARARGS, "Remove"},
679         {"set_solo", (PyCFunction)OutputChannel_set_solo, METH_VARARGS, "Set a channel as solo"},
680         {"set_muted", (PyCFunction)OutputChannel_set_muted, METH_VARARGS, "Set a channel as muted"},
681         {"is_solo", (PyCFunction)OutputChannel_is_solo, METH_VARARGS, "Is a channel set as solo"},
682         {"is_muted", (PyCFunction)OutputChannel_is_muted, METH_VARARGS, "Is a channel set as muted"},
683         {NULL}
684 };
685
686 static PyTypeObject OutputChannelType = {
687         PyObject_HEAD_INIT(NULL)
688         0,       /*ob_size*/
689         "jack_mixer_c.OutputChannel",    /*tp_name*/
690         sizeof(OutputChannelObject), /*tp_basicsize*/
691         0,       /*tp_itemsize*/
692         0,       /*tp_dealloc*/
693         0,       /*tp_print*/
694         0,       /*tp_getattr*/
695         0,       /*tp_setattr*/
696         0,       /*tp_compare*/
697         0,       /*tp_repr*/
698         0,       /*tp_as_number*/
699         0,       /*tp_as_sequence*/
700         0,       /*tp_as_mapping*/
701         0,       /*tp_hash */
702         0,       /*tp_call*/
703         0,       /*tp_str*/
704         0,       /*tp_getattro*/
705         0,       /*tp_setattro*/
706         0,       /*tp_as_buffer*/
707         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
708         "Output Channel objects",           /* tp_doc */
709         0,                         /* tp_traverse */
710         0,                         /* tp_clear */
711         0,                         /* tp_richcompare */
712         0,                         /* tp_weaklistoffset */
713         0,                         /* tp_iter */
714         0,                         /* tp_iternext */
715         output_channel_methods,    /* tp_methods */
716         0,             /* tp_members */
717         OutputChannel_getseters,   /* tp_getset */
718         &ChannelType,              /* tp_base */
719         0,                         /* tp_dict */
720         0,                         /* tp_descr_get */
721         0,                         /* tp_descr_set */
722         0,                         /* tp_dictoffset */
723         0,                         /* tp_init */
724         0,                         /* tp_alloc */
725         0,                         /* tp_new */
726 };
727
728 static PyObject*
729 OutputChannel_New(jack_mixer_output_channel_t output_channel)
730 {
731         OutputChannelObject *self;
732         self = (OutputChannelObject*)PyObject_NEW(OutputChannelObject, &OutputChannelType);
733         if (self != NULL) {
734                 self->midi_change_callback = NULL;
735                 self->output_channel = output_channel;
736         }
737         return (PyObject*)self;
738 }
739
740
741 /** Mixer Type **/
742
743 typedef struct {
744         PyObject_HEAD
745         PyObject *main_mix_channel;
746         jack_mixer_t mixer;
747 } MixerObject;
748
749 static void
750 Mixer_dealloc(MixerObject *self)
751 {
752         Py_XDECREF(self->main_mix_channel);
753         if (self->mixer)
754                 destroy(self->mixer);
755         self->ob_type->tp_free((PyObject*)self);
756 }
757
758 static PyObject*
759 Mixer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
760 {
761         MixerObject *self;
762
763         self = (MixerObject*)type->tp_alloc(type, 0);
764
765         if (self != NULL) {
766                 self->main_mix_channel = NULL;
767                 self->mixer = NULL;
768         }
769
770         return (PyObject*)self;
771 }
772
773 static int
774 Mixer_init(MixerObject *self, PyObject *args, PyObject *kwds)
775 {
776         static char *kwlist[] = {"name", NULL};
777         char *name;
778
779         if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &name))
780                 return -1;
781         
782         self->mixer = create(name);
783         if (self->mixer == NULL) {
784                 PyErr_SetString(PyExc_RuntimeError,
785                                 "error creating mixer, probably jack is not running");
786                 return -1;
787         }
788
789         self->main_mix_channel = Channel_New(get_main_mix_channel(self->mixer));
790
791         return 0;
792 }
793
794 static PyMemberDef Mixer_members[] = {
795         {"main_mix_channel", T_OBJECT, offsetof(MixerObject, main_mix_channel), 0, "main_mix_channel"},
796         {NULL}
797 };
798
799 static PyObject*
800 Mixer_get_channels_count(MixerObject *self, void *closure)
801 {
802         return PyInt_FromLong(get_channels_count(self->mixer));
803 }
804
805 static PyObject*
806 Mixer_get_last_midi_channel(MixerObject *self, void *closure)
807 {
808         return PyInt_FromLong(get_last_midi_channel(self->mixer));
809 }
810
811
812 static PyGetSetDef Mixer_getseters[] = {
813         {"channels_count", (getter)Mixer_get_channels_count, NULL,
814                 "channels count", NULL},
815         {"last_midi_channel", (getter)Mixer_get_last_midi_channel, NULL,
816                 "last midi channel", NULL},
817         {NULL}
818 };
819
820 static PyObject*
821 Mixer_add_channel(MixerObject *self, PyObject *args)
822 {
823         char *name;
824         int stereo;
825         jack_mixer_channel_t channel;
826
827         if (! PyArg_ParseTuple(args, "sb", &name, &stereo)) return NULL;
828
829         channel = add_channel(self->mixer, name, (bool)stereo);
830
831         if (channel == NULL) {
832                 PyErr_SetString(PyExc_RuntimeError, "error adding channel");
833                 return NULL;
834         }
835
836         return Channel_New(channel);
837 }
838
839 static PyObject*
840 Mixer_add_output_channel(MixerObject *self, PyObject *args)
841 {
842         char *name;
843         int stereo = 1;
844         int system = 0;
845         jack_mixer_output_channel_t channel;
846
847         if (! PyArg_ParseTuple(args, "s|bb", &name, &stereo, &system)) return NULL;
848
849         channel = add_output_channel(self->mixer, name, (bool)stereo, (bool)system);
850
851         return OutputChannel_New(channel);
852 }
853
854
855 static PyMethodDef Mixer_methods[] = {
856         {"add_channel", (PyCFunction)Mixer_add_channel, METH_VARARGS, "Add a new channel"},
857         {"add_output_channel", (PyCFunction)Mixer_add_output_channel, METH_VARARGS, "Add a new output channel"},
858 //      {"remove_channel", (PyCFunction)Mixer_remove_channel, METH_VARARGS, "Remove a channel"},
859         {NULL}
860 };
861
862 static PyTypeObject MixerType = {
863         PyObject_HEAD_INIT(NULL)
864         0,       /*ob_size*/
865         "jack_mixer_c.Mixer",    /*tp_name*/
866         sizeof(MixerObject), /*tp_basicsize*/
867         0,       /*tp_itemsize*/
868         (destructor)Mixer_dealloc,       /*tp_dealloc*/
869         0,       /*tp_print*/
870         0,       /*tp_getattr*/
871         0,       /*tp_setattr*/
872         0,       /*tp_compare*/
873         0,       /*tp_repr*/
874         0,       /*tp_as_number*/
875         0,       /*tp_as_sequence*/
876         0,       /*tp_as_mapping*/
877         0,       /*tp_hash */
878         0,       /*tp_call*/
879         0,       /*tp_str*/
880         0,       /*tp_getattro*/
881         0,       /*tp_setattro*/
882         0,       /*tp_as_buffer*/
883         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
884         "Mixer objects",           /* tp_doc */
885         0,                         /* tp_traverse */
886         0,                         /* tp_clear */
887         0,                         /* tp_richcompare */
888         0,                         /* tp_weaklistoffset */
889         0,                         /* tp_iter */
890         0,                         /* tp_iternext */
891         Mixer_methods,             /* tp_methods */
892         Mixer_members,             /* tp_members */
893         Mixer_getseters,           /* tp_getset */
894         0,                         /* tp_base */
895         0,                         /* tp_dict */
896         0,                         /* tp_descr_get */
897         0,                         /* tp_descr_set */
898         0,                         /* tp_dictoffset */
899         (initproc)Mixer_init,      /* tp_init */
900         0,                         /* tp_alloc */
901         Mixer_new,                 /* tp_new */
902 };
903
904
905 static PyMethodDef jack_mixer_methods[] = {
906         {NULL}  /* Sentinel */
907 };
908
909
910
911 PyMODINIT_FUNC initjack_mixer_c(void)
912 {
913         PyObject *m;
914
915         if (PyType_Ready(&MixerType) < 0)
916                 return;
917         if (PyType_Ready(&ChannelType) < 0)
918                 return;
919         if (PyType_Ready(&OutputChannelType) < 0)
920                 return;
921         if (PyType_Ready(&ScaleType) < 0)
922                 return;
923         
924         m = Py_InitModule3("jack_mixer_c", jack_mixer_methods, "Jack Mixer C Helper Module");
925
926         Py_INCREF(&MixerType);
927         PyModule_AddObject(m, "Mixer", (PyObject*)&MixerType);
928         Py_INCREF(&ChannelType);
929         PyModule_AddObject(m, "Channel", (PyObject*)&ChannelType);
930         Py_INCREF(&OutputChannelType);
931         PyModule_AddObject(m, "OutputChannel", (PyObject*)&OutputChannelType);
932         Py_INCREF(&ScaleType);
933         PyModule_AddObject(m, "Scale", (PyObject*)&ScaleType);
934 }
935