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