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