2 * This file is part of jack_mixer
4 * Copyright (C) 2009 Frederic Peters <fpeters@0d.be>
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
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.
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.
26 #include <structmember.h>
28 #include "jack_mixer.h"
35 jack_mixer_scale_t scale;
39 Scale_dealloc(ScaleObject *self)
42 scale_destroy(self->scale);
43 self->ob_type->tp_free((PyObject*)self);
47 Scale_init(ScaleObject *self, PyObject *args, PyObject *kwds)
49 self->scale = scale_create();
54 Scale_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
58 self = (ScaleObject*)type->tp_alloc(type, 0);
60 return (PyObject*)self;
64 Scale_add_threshold(ScaleObject *self, PyObject *args)
66 float db, scale_value;
68 if (! PyArg_ParseTuple(args, "ff", &db, &scale_value)) return NULL;
70 scale_add_threshold(self->scale, db, scale_value);
77 Scale_calculate_coefficients(ScaleObject *self, PyObject *args)
79 if (! PyArg_ParseTuple(args, "")) return NULL;
80 scale_calculate_coefficients(self->scale);
86 Scale_db_to_scale(ScaleObject *self, PyObject *args)
89 if (! PyArg_ParseTuple(args, "d", &db)) return NULL;
90 return PyFloat_FromDouble(scale_db_to_scale(self->scale, db));
94 Scale_scale_to_db(ScaleObject *self, PyObject *args)
97 if (! PyArg_ParseTuple(args, "d", &scale_value)) return NULL;
98 return PyFloat_FromDouble(scale_scale_to_db(self->scale, scale_value));
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"},
110 static PyTypeObject ScaleType = {
111 PyObject_HEAD_INIT(NULL)
113 "jack_mixer_c.Scale", /*tp_name*/
114 sizeof(ScaleObject), /*tp_basicsize*/
116 (destructor)Scale_dealloc, /*tp_dealloc*/
123 0, /*tp_as_sequence*/
131 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
132 "Scale objects", /* tp_doc */
135 0, /* tp_richcompare */
136 0, /* tp_weaklistoffset */
139 Scale_methods, /* tp_methods */
144 0, /* tp_descr_get */
145 0, /* tp_descr_set */
146 0, /* tp_dictoffset */
147 (initproc)Scale_init, /* tp_init */
149 Scale_new, /* tp_new */
157 PyObject *midi_change_callback;
158 jack_mixer_channel_t channel;
162 Channel_dealloc(ChannelObject *self)
164 Py_XDECREF(self->midi_change_callback);
165 self->ob_type->tp_free((PyObject*)self);
169 Channel_init(ChannelObject *self, PyObject *args, PyObject *kwds)
171 self->midi_change_callback = NULL;
176 Channel_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
180 self = (ChannelObject*)type->tp_alloc(type, 0);
183 self->channel = NULL;
184 self->midi_change_callback = NULL;
187 return (PyObject*)self;
191 Channel_get_is_stereo(ChannelObject *self, void *closure)
195 bool is_stereo = channel_is_stereo(self->channel);
206 Channel_get_volume(ChannelObject *self, void *closure)
208 return PyFloat_FromDouble(channel_volume_read(self->channel));
212 Channel_set_volume(ChannelObject *self, PyObject *value, void *closure)
214 if (self->channel == NULL) {
215 PyErr_SetString(PyExc_RuntimeError, "unitialized channel");
218 channel_volume_write(self->channel, PyFloat_AsDouble(value));
223 Channel_get_balance(ChannelObject *self, void *closure)
225 return PyFloat_FromDouble(channel_balance_read(self->channel));
229 Channel_set_balance(ChannelObject *self, PyObject *value, void *closure)
231 channel_balance_write(self->channel, PyFloat_AsDouble(value));
236 Channel_get_out_mute(ChannelObject *self, void *closure)
240 if (channel_is_out_muted(self->channel)) {
250 Channel_set_out_mute(ChannelObject *self, PyObject *value, void *closure)
252 if (value == Py_True) {
253 channel_out_mute(self->channel);
255 channel_out_unmute(self->channel);
261 Channel_get_solo(ChannelObject *self, void *closure)
265 if (channel_is_soloed(self->channel)) {
275 Channel_set_solo(ChannelObject *self, PyObject *value, void *closure)
277 if (value == Py_True) {
278 channel_solo(self->channel);
280 channel_unsolo(self->channel);
286 Channel_get_meter(ChannelObject *self, void *closure)
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));
297 result = PyTuple_New(1);
298 channel_mono_meter_read(self->channel, &left);
299 PyTuple_SetItem(result, 0, PyFloat_FromDouble(left));
305 Channel_get_abspeak(ChannelObject *self, void *closure)
307 return PyFloat_FromDouble(channel_abspeak_read(self->channel));
311 Channel_set_abspeak(ChannelObject *self, PyObject *value, void *closure)
313 if (value != Py_None) {
314 fprintf(stderr, "abspeak can only be reset (set to None)\n");
317 channel_abspeak_reset(self->channel);
322 Channel_set_midi_scale(ChannelObject *self, PyObject *value, void *closure)
324 ScaleObject *scale_object = (ScaleObject*)value; /* XXX: check */
326 channel_set_midi_scale(self->channel, scale_object->scale);
332 Channel_get_midi_change_callback(ChannelObject *self, void *closure)
334 if (self->midi_change_callback) {
335 Py_INCREF(self->midi_change_callback);
336 return self->midi_change_callback;
344 channel_midi_callback(void *userdata)
346 ChannelObject *self = (ChannelObject*)userdata;
347 PyGILState_STATE gstate;
349 gstate = PyGILState_Ensure();
350 PyObject_CallObject(self->midi_change_callback, NULL);
351 PyGILState_Release(gstate);
355 Channel_set_midi_change_callback(ChannelObject *self, PyObject *value, void *closure)
357 if (value == Py_None) {
358 self->midi_change_callback = NULL;
359 channel_set_midi_change_callback(self->channel, NULL, NULL);
361 if (!PyCallable_Check(value)) {
362 PyErr_SetString(PyExc_TypeError, "value must be callable");
365 if (self->midi_change_callback) {
366 Py_XDECREF(self->midi_change_callback);
369 self->midi_change_callback = value;
370 channel_set_midi_change_callback(self->channel,
371 channel_midi_callback, self);
378 Channel_get_name(ChannelObject *self, void *closure)
380 return PyString_FromString(channel_get_name(self->channel));
384 Channel_set_name(ChannelObject *self, PyObject *value, void *closure)
386 channel_rename(self->channel, PyString_AsString(value));
391 Channel_get_balance_midi_cc(ChannelObject *self, void *closure)
393 return PyInt_FromLong(channel_get_balance_midi_cc(self->channel));
397 Channel_set_balance_midi_cc(ChannelObject *self, PyObject *value, void *closure)
402 new_cc = PyInt_AsLong(value);
403 result = channel_set_balance_midi_cc(self->channel, new_cc);
408 PyErr_SetString(PyExc_RuntimeError, "value out of range");
414 Channel_get_volume_midi_cc(ChannelObject *self, void *closure)
416 return PyInt_FromLong(channel_get_volume_midi_cc(self->channel));
420 Channel_set_volume_midi_cc(ChannelObject *self, PyObject *value, void *closure)
425 new_cc = PyInt_AsLong(value);
426 result = channel_set_volume_midi_cc(self->channel, new_cc);
431 PyErr_SetString(PyExc_RuntimeError, "value out of range");
437 Channel_get_mute_midi_cc(ChannelObject *self, void *closure)
439 return PyInt_FromLong(channel_get_mute_midi_cc(self->channel));
443 Channel_set_mute_midi_cc(ChannelObject *self, PyObject *value, void *closure)
448 new_cc = PyInt_AsLong(value);
449 result = channel_set_mute_midi_cc(self->channel, new_cc);
454 PyErr_SetString(PyExc_RuntimeError, "value out of range");
460 Channel_get_solo_midi_cc(ChannelObject *self, void *closure)
462 return PyInt_FromLong(channel_get_solo_midi_cc(self->channel));
466 Channel_set_solo_midi_cc(ChannelObject *self, PyObject *value, void *closure)
471 new_cc = PyInt_AsLong(value);
472 result = channel_set_solo_midi_cc(self->channel, new_cc);
477 PyErr_SetString(PyExc_RuntimeError, "value out of range");
483 Channel_get_midi_in_got_events(ChannelObject *self, void *closure)
487 if (channel_get_midi_in_got_events(self->channel)) {
496 static PyGetSetDef Channel_getseters[] = {
498 (getter)Channel_get_is_stereo, NULL,
499 "mono/stereo", NULL},
501 (getter)Channel_get_volume, (setter)Channel_set_volume,
504 (getter)Channel_get_balance, (setter)Channel_set_balance,
507 (getter)Channel_get_out_mute, (setter)Channel_set_out_mute,
510 (getter)Channel_get_solo, (setter)Channel_set_solo,
513 (getter)Channel_get_meter, NULL,
516 (getter)Channel_get_abspeak, (setter)Channel_set_abspeak,
519 NULL, (setter)Channel_set_midi_scale,
521 {"midi_change_callback",
522 (getter)Channel_get_midi_change_callback,
523 (setter)Channel_set_midi_change_callback,
524 "midi change callback", NULL},
526 (getter)Channel_get_name,
527 (setter)Channel_set_name,
530 (getter)Channel_get_balance_midi_cc,
531 (setter)Channel_set_balance_midi_cc,
532 "Balance MIDI CC", NULL},
534 (getter)Channel_get_volume_midi_cc,
535 (setter)Channel_set_volume_midi_cc,
536 "Volume MIDI CC", NULL},
538 (getter)Channel_get_mute_midi_cc,
539 (setter)Channel_set_mute_midi_cc,
540 "Mute MIDI CC", NULL},
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},
552 Channel_remove(ChannelObject *self, PyObject *args)
554 if (! PyArg_ParseTuple(args, "")) return NULL;
555 remove_channel(self->channel);
561 Channel_autoset_midi_cc(ChannelObject *self, PyObject *args)
563 if (! PyArg_ParseTuple(args, "")) return NULL;
564 channel_autoset_midi_cc(self->channel);
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"},
575 static PyTypeObject ChannelType = {
576 PyObject_HEAD_INIT(NULL)
578 "jack_mixer_c.Channel", /*tp_name*/
579 sizeof(ChannelObject), /*tp_basicsize*/
581 (destructor)Channel_dealloc, /*tp_dealloc*/
588 0, /*tp_as_sequence*/
596 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
597 "Channel objects", /* tp_doc */
600 0, /* tp_richcompare */
601 0, /* tp_weaklistoffset */
604 channel_methods, /* tp_methods */
606 Channel_getseters, /* tp_getset */
609 0, /* tp_descr_get */
610 0, /* tp_descr_set */
611 0, /* tp_dictoffset */
612 (initproc)Channel_init, /* tp_init */
614 Channel_new, /* tp_new */
618 Channel_New(jack_mixer_channel_t channel)
621 self = (ChannelObject*)PyObject_NEW(ChannelObject, &ChannelType);
623 self->channel = channel;
624 self->midi_change_callback = NULL;
626 return (PyObject*)self;
629 /** Output Channel Type **/
633 PyObject *midi_change_callback;
634 jack_mixer_output_channel_t *output_channel;
635 } OutputChannelObject;
638 OutputChannel_set_prefader(OutputChannelObject *self, PyObject *value, void *closure)
640 if (value == Py_True) {
641 output_channel_set_prefader(self->output_channel, true);
643 output_channel_set_prefader(self->output_channel, false);
649 OutputChannel_get_prefader(OutputChannelObject *self, void *closure)
653 if (output_channel_is_prefader(self->output_channel)) {
662 static PyGetSetDef OutputChannel_getseters[] = {
664 (getter)OutputChannel_get_prefader, (setter)OutputChannel_set_prefader,
670 OutputChannel_remove(OutputChannelObject *self, PyObject *args)
672 if (! PyArg_ParseTuple(args, "")) return NULL;
673 remove_output_channel(self->output_channel);
679 OutputChannel_set_solo(OutputChannelObject *self, PyObject *args)
684 if (! PyArg_ParseTuple(args, "Ob", &channel, &solo)) return NULL;
686 output_channel_set_solo(self->output_channel,
687 ((ChannelObject*)channel)->channel,
695 OutputChannel_set_muted(OutputChannelObject *self, PyObject *args)
700 if (! PyArg_ParseTuple(args, "Ob", &channel, &muted)) return NULL;
702 output_channel_set_muted(self->output_channel,
703 ((ChannelObject*)channel)->channel,
711 OutputChannel_is_solo(OutputChannelObject *self, PyObject *args)
716 if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
718 if (output_channel_is_solo(self->output_channel,
719 ((ChannelObject*)channel)->channel)) {
730 OutputChannel_is_muted(OutputChannelObject *self, PyObject *args)
735 if (! PyArg_ParseTuple(args, "O", &channel)) return NULL;
737 if (output_channel_is_muted(self->output_channel,
738 ((ChannelObject*)channel)->channel)) {
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"},
757 static PyTypeObject OutputChannelType = {
758 PyObject_HEAD_INIT(NULL)
760 "jack_mixer_c.OutputChannel", /*tp_name*/
761 sizeof(OutputChannelObject), /*tp_basicsize*/
770 0, /*tp_as_sequence*/
778 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
779 "Output Channel objects", /* tp_doc */
782 0, /* tp_richcompare */
783 0, /* tp_weaklistoffset */
786 output_channel_methods, /* tp_methods */
788 OutputChannel_getseters, /* tp_getset */
789 &ChannelType, /* tp_base */
791 0, /* tp_descr_get */
792 0, /* tp_descr_set */
793 0, /* tp_dictoffset */
800 OutputChannel_New(jack_mixer_output_channel_t output_channel)
802 OutputChannelObject *self;
803 self = (OutputChannelObject*)PyObject_NEW(OutputChannelObject, &OutputChannelType);
805 self->midi_change_callback = NULL;
806 self->output_channel = output_channel;
808 return (PyObject*)self;
820 Mixer_dealloc(MixerObject *self)
823 destroy(self->mixer);
824 self->ob_type->tp_free((PyObject*)self);
828 Mixer_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
832 self = (MixerObject*)type->tp_alloc(type, 0);
838 return (PyObject*)self;
842 Mixer_init(MixerObject *self, PyObject *args, PyObject *kwds)
844 static char *kwlist[] = {"name", "stereo", NULL};
848 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|b", kwlist, &name, &stereo))
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");
861 static PyMemberDef Mixer_members[] = {
866 Mixer_get_channels_count(MixerObject *self, void *closure)
868 return PyInt_FromLong(get_channels_count(self->mixer));
872 Mixer_get_client_name(MixerObject *self, void *closure)
874 return PyString_FromString(get_client_name(self->mixer));
878 Mixer_get_last_midi_channel(MixerObject *self, void *closure)
880 return PyInt_FromLong(get_last_midi_channel(self->mixer));
884 Mixer_set_last_midi_channel(MixerObject *self, PyObject *value, void *closure)
889 new_channel = PyInt_AsLong(value);
890 result = set_last_midi_channel(self->mixer, new_channel);
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},
906 Mixer_add_channel(MixerObject *self, PyObject *args)
910 jack_mixer_channel_t channel;
912 if (! PyArg_ParseTuple(args, "si", &name, &stereo)) return NULL;
914 channel = add_channel(self->mixer, name, (bool)stereo);
916 if (channel == NULL) {
917 PyErr_SetString(PyExc_RuntimeError, "error adding channel");
921 return Channel_New(channel);
925 Mixer_add_output_channel(MixerObject *self, PyObject *args)
930 jack_mixer_output_channel_t channel;
932 if (! PyArg_ParseTuple(args, "s|bb", &name, &stereo, &system)) return NULL;
934 channel = add_output_channel(self->mixer, name, (bool)stereo, (bool)system);
936 return OutputChannel_New(channel);
940 Mixer_destroy(MixerObject *self, PyObject *args)
943 destroy(self->mixer);
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"},
959 static PyTypeObject MixerType = {
960 PyObject_HEAD_INIT(NULL)
962 "jack_mixer_c.Mixer", /*tp_name*/
963 sizeof(MixerObject), /*tp_basicsize*/
965 (destructor)Mixer_dealloc, /*tp_dealloc*/
972 0, /*tp_as_sequence*/
980 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
981 "Mixer objects", /* tp_doc */
984 0, /* tp_richcompare */
985 0, /* tp_weaklistoffset */
988 Mixer_methods, /* tp_methods */
989 Mixer_members, /* tp_members */
990 Mixer_getseters, /* tp_getset */
993 0, /* tp_descr_get */
994 0, /* tp_descr_set */
995 0, /* tp_dictoffset */
996 (initproc)Mixer_init, /* tp_init */
998 Mixer_new, /* tp_new */
1002 static PyMethodDef jack_mixer_methods[] = {
1003 {NULL} /* Sentinel */
1008 PyMODINIT_FUNC initjack_mixer_c(void)
1012 if (PyType_Ready(&MixerType) < 0)
1014 if (PyType_Ready(&ChannelType) < 0)
1016 if (PyType_Ready(&OutputChannelType) < 0)
1018 if (PyType_Ready(&ScaleType) < 0)
1021 m = Py_InitModule3("jack_mixer_c", jack_mixer_methods, "Jack Mixer C Helper Module");
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);