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_mute(ChannelObject
*self
, void *closure
)
240 if (channel_is_muted(self
->channel
)) {
250 Channel_set_mute(ChannelObject
*self
, PyObject
*value
, void *closure
)
252 if (value
== Py_True
) {
253 channel_mute(self
->channel
);
255 channel_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 already in use");
409 } else if (result
== 2) {
410 PyErr_SetString(PyExc_RuntimeError
, "value out of range");
416 Channel_get_volume_midi_cc(ChannelObject
*self
, void *closure
)
418 return PyInt_FromLong(channel_get_volume_midi_cc(self
->channel
));
422 Channel_set_volume_midi_cc(ChannelObject
*self
, PyObject
*value
, void *closure
)
427 new_cc
= PyInt_AsLong(value
);
428 result
= channel_set_volume_midi_cc(self
->channel
, new_cc
);
433 PyErr_SetString(PyExc_RuntimeError
, "value already in use");
434 } else if (result
== 2) {
435 PyErr_SetString(PyExc_RuntimeError
, "value out of range");
441 Channel_get_midi_in_got_events(ChannelObject
*self
, void *closure
)
445 if (channel_get_midi_in_got_events(self
->channel
)) {
455 static PyGetSetDef Channel_getseters
[] = {
457 (getter
)Channel_get_is_stereo
, NULL
,
458 "mono/stereo", NULL
},
460 (getter
)Channel_get_volume
, (setter
)Channel_set_volume
,
463 (getter
)Channel_get_balance
, (setter
)Channel_set_balance
,
466 (getter
)Channel_get_mute
, (setter
)Channel_set_mute
,
469 (getter
)Channel_get_solo
, (setter
)Channel_set_solo
,
472 (getter
)Channel_get_meter
, NULL
,
475 (getter
)Channel_get_abspeak
, (setter
)Channel_set_abspeak
,
478 NULL
, (setter
)Channel_set_midi_scale
,
480 {"midi_change_callback",
481 (getter
)Channel_get_midi_change_callback
,
482 (setter
)Channel_set_midi_change_callback
,
483 "midi change callback", NULL
},
485 (getter
)Channel_get_name
,
486 (setter
)Channel_set_name
,
489 (getter
)Channel_get_balance_midi_cc
,
490 (setter
)Channel_set_balance_midi_cc
,
491 "Balance MIDI CC", NULL
},
493 (getter
)Channel_get_volume_midi_cc
,
494 (setter
)Channel_set_volume_midi_cc
,
495 "Volume MIDI CC", NULL
},
496 {"midi_in_got_events",
497 (getter
)Channel_get_midi_in_got_events
, NULL
,
498 "Got new MIDI IN events", NULL
},
503 Channel_remove(ChannelObject
*self
, PyObject
*args
)
505 if (! PyArg_ParseTuple(args
, "")) return NULL
;
506 remove_channel(self
->channel
);
512 Channel_autoset_midi_cc(ChannelObject
*self
, PyObject
*args
)
514 if (! PyArg_ParseTuple(args
, "")) return NULL
;
515 channel_autoset_midi_cc(self
->channel
);
520 static PyMethodDef channel_methods
[] = {
521 {"remove", (PyCFunction
)Channel_remove
, METH_VARARGS
, "Remove"},
522 {"autoset_midi_cc", (PyCFunction
)Channel_autoset_midi_cc
, METH_VARARGS
, "Autoset MIDI CC"},
526 static PyTypeObject ChannelType
= {
527 PyObject_HEAD_INIT(NULL
)
529 "jack_mixer_c.Channel", /*tp_name*/
530 sizeof(ChannelObject
), /*tp_basicsize*/
532 (destructor
)Channel_dealloc
, /*tp_dealloc*/
539 0, /*tp_as_sequence*/
547 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /*tp_flags*/
548 "Channel objects", /* tp_doc */
551 0, /* tp_richcompare */
552 0, /* tp_weaklistoffset */
555 channel_methods
, /* tp_methods */
557 Channel_getseters
, /* tp_getset */
560 0, /* tp_descr_get */
561 0, /* tp_descr_set */
562 0, /* tp_dictoffset */
563 (initproc
)Channel_init
, /* tp_init */
565 Channel_new
, /* tp_new */
569 Channel_New(jack_mixer_channel_t channel
)
572 self
= (ChannelObject
*)PyObject_NEW(ChannelObject
, &ChannelType
);
574 self
->channel
= channel
;
575 self
->midi_change_callback
= NULL
;
577 return (PyObject
*)self
;
580 /** Output Channel Type **/
584 PyObject
*midi_change_callback
;
585 jack_mixer_output_channel_t
*output_channel
;
586 } OutputChannelObject
;
589 OutputChannel_set_prefader(OutputChannelObject
*self
, PyObject
*value
, void *closure
)
591 if (value
== Py_True
) {
592 output_channel_set_prefader(self
->output_channel
, true);
594 output_channel_set_prefader(self
->output_channel
, false);
600 OutputChannel_get_prefader(OutputChannelObject
*self
, void *closure
)
604 if (output_channel_is_prefader(self
->output_channel
)) {
613 static PyGetSetDef OutputChannel_getseters
[] = {
615 (getter
)OutputChannel_get_prefader
, (setter
)OutputChannel_set_prefader
,
621 OutputChannel_remove(OutputChannelObject
*self
, PyObject
*args
)
623 if (! PyArg_ParseTuple(args
, "")) return NULL
;
624 remove_output_channel(self
->output_channel
);
630 OutputChannel_set_solo(OutputChannelObject
*self
, PyObject
*args
)
635 if (! PyArg_ParseTuple(args
, "Ob", &channel
, &solo
)) return NULL
;
637 output_channel_set_solo(self
->output_channel
,
638 ((ChannelObject
*)channel
)->channel
,
646 OutputChannel_set_muted(OutputChannelObject
*self
, PyObject
*args
)
651 if (! PyArg_ParseTuple(args
, "Ob", &channel
, &muted
)) return NULL
;
653 output_channel_set_muted(self
->output_channel
,
654 ((ChannelObject
*)channel
)->channel
,
662 OutputChannel_is_solo(OutputChannelObject
*self
, PyObject
*args
)
667 if (! PyArg_ParseTuple(args
, "O", &channel
)) return NULL
;
669 if (output_channel_is_solo(self
->output_channel
,
670 ((ChannelObject
*)channel
)->channel
)) {
681 OutputChannel_is_muted(OutputChannelObject
*self
, PyObject
*args
)
686 if (! PyArg_ParseTuple(args
, "O", &channel
)) return NULL
;
688 if (output_channel_is_muted(self
->output_channel
,
689 ((ChannelObject
*)channel
)->channel
)) {
699 static PyMethodDef output_channel_methods
[] = {
700 {"remove", (PyCFunction
)OutputChannel_remove
, METH_VARARGS
, "Remove"},
701 {"set_solo", (PyCFunction
)OutputChannel_set_solo
, METH_VARARGS
, "Set a channel as solo"},
702 {"set_muted", (PyCFunction
)OutputChannel_set_muted
, METH_VARARGS
, "Set a channel as muted"},
703 {"is_solo", (PyCFunction
)OutputChannel_is_solo
, METH_VARARGS
, "Is a channel set as solo"},
704 {"is_muted", (PyCFunction
)OutputChannel_is_muted
, METH_VARARGS
, "Is a channel set as muted"},
708 static PyTypeObject OutputChannelType
= {
709 PyObject_HEAD_INIT(NULL
)
711 "jack_mixer_c.OutputChannel", /*tp_name*/
712 sizeof(OutputChannelObject
), /*tp_basicsize*/
721 0, /*tp_as_sequence*/
729 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /*tp_flags*/
730 "Output Channel objects", /* tp_doc */
733 0, /* tp_richcompare */
734 0, /* tp_weaklistoffset */
737 output_channel_methods
, /* tp_methods */
739 OutputChannel_getseters
, /* tp_getset */
740 &ChannelType
, /* tp_base */
742 0, /* tp_descr_get */
743 0, /* tp_descr_set */
744 0, /* tp_dictoffset */
751 OutputChannel_New(jack_mixer_output_channel_t output_channel
)
753 OutputChannelObject
*self
;
754 self
= (OutputChannelObject
*)PyObject_NEW(OutputChannelObject
, &OutputChannelType
);
756 self
->midi_change_callback
= NULL
;
757 self
->output_channel
= output_channel
;
759 return (PyObject
*)self
;
767 PyObject
*main_mix_channel
;
772 Mixer_dealloc(MixerObject
*self
)
774 Py_XDECREF(self
->main_mix_channel
);
776 destroy(self
->mixer
);
777 self
->ob_type
->tp_free((PyObject
*)self
);
781 Mixer_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
785 self
= (MixerObject
*)type
->tp_alloc(type
, 0);
788 self
->main_mix_channel
= NULL
;
792 return (PyObject
*)self
;
796 Mixer_init(MixerObject
*self
, PyObject
*args
, PyObject
*kwds
)
798 static char *kwlist
[] = {"name", "stereo", NULL
};
802 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "s|b", kwlist
, &name
, &stereo
))
805 self
->mixer
= create(name
, (bool)stereo
);
806 if (self
->mixer
== NULL
) {
807 PyErr_SetString(PyExc_RuntimeError
,
808 "error creating mixer, probably jack is not running");
812 self
->main_mix_channel
= Channel_New(get_main_mix_channel(self
->mixer
));
817 static PyMemberDef Mixer_members
[] = {
818 {"main_mix_channel", T_OBJECT
, offsetof(MixerObject
, main_mix_channel
), 0, "main_mix_channel"},
823 Mixer_get_channels_count(MixerObject
*self
, void *closure
)
825 return PyInt_FromLong(get_channels_count(self
->mixer
));
829 Mixer_get_client_name(MixerObject
*self
, void *closure
)
831 return PyString_FromString(get_client_name(self
->mixer
));
835 Mixer_get_last_midi_channel(MixerObject
*self
, void *closure
)
837 return PyInt_FromLong(get_last_midi_channel(self
->mixer
));
841 static PyGetSetDef Mixer_getseters
[] = {
842 {"channels_count", (getter
)Mixer_get_channels_count
, NULL
,
843 "channels count", NULL
},
844 {"last_midi_channel", (getter
)Mixer_get_last_midi_channel
, NULL
,
845 "last midi channel", NULL
},
850 Mixer_add_channel(MixerObject
*self
, PyObject
*args
)
854 jack_mixer_channel_t channel
;
856 if (! PyArg_ParseTuple(args
, "si", &name
, &stereo
)) return NULL
;
858 channel
= add_channel(self
->mixer
, name
, (bool)stereo
);
860 if (channel
== NULL
) {
861 PyErr_SetString(PyExc_RuntimeError
, "error adding channel");
865 return Channel_New(channel
);
869 Mixer_add_output_channel(MixerObject
*self
, PyObject
*args
)
874 jack_mixer_output_channel_t channel
;
876 if (! PyArg_ParseTuple(args
, "s|bb", &name
, &stereo
, &system
)) return NULL
;
878 channel
= add_output_channel(self
->mixer
, name
, (bool)stereo
, (bool)system
);
880 return OutputChannel_New(channel
);
884 Mixer_destroy(MixerObject
*self
, PyObject
*args
)
887 destroy(self
->mixer
);
894 static PyMethodDef Mixer_methods
[] = {
895 {"add_channel", (PyCFunction
)Mixer_add_channel
, METH_VARARGS
, "Add a new channel"},
896 {"add_output_channel", (PyCFunction
)Mixer_add_output_channel
, METH_VARARGS
, "Add a new output channel"},
897 {"destroy", (PyCFunction
)Mixer_destroy
, METH_VARARGS
, "Destroy JACK Mixer"},
898 {"client_name", (PyCFunction
)Mixer_get_client_name
, METH_VARARGS
, "Get jack client name"},
899 // {"remove_channel", (PyCFunction)Mixer_remove_channel, METH_VARARGS, "Remove a channel"},
903 static PyTypeObject MixerType
= {
904 PyObject_HEAD_INIT(NULL
)
906 "jack_mixer_c.Mixer", /*tp_name*/
907 sizeof(MixerObject
), /*tp_basicsize*/
909 (destructor
)Mixer_dealloc
, /*tp_dealloc*/
916 0, /*tp_as_sequence*/
924 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /*tp_flags*/
925 "Mixer objects", /* tp_doc */
928 0, /* tp_richcompare */
929 0, /* tp_weaklistoffset */
932 Mixer_methods
, /* tp_methods */
933 Mixer_members
, /* tp_members */
934 Mixer_getseters
, /* tp_getset */
937 0, /* tp_descr_get */
938 0, /* tp_descr_set */
939 0, /* tp_dictoffset */
940 (initproc
)Mixer_init
, /* tp_init */
942 Mixer_new
, /* tp_new */
946 static PyMethodDef jack_mixer_methods
[] = {
947 {NULL
} /* Sentinel */
952 PyMODINIT_FUNC
initjack_mixer_c(void)
956 if (PyType_Ready(&MixerType
) < 0)
958 if (PyType_Ready(&ChannelType
) < 0)
960 if (PyType_Ready(&OutputChannelType
) < 0)
962 if (PyType_Ready(&ScaleType
) < 0)
965 m
= Py_InitModule3("jack_mixer_c", jack_mixer_methods
, "Jack Mixer C Helper Module");
967 Py_INCREF(&MixerType
);
968 PyModule_AddObject(m
, "Mixer", (PyObject
*)&MixerType
);
969 Py_INCREF(&ChannelType
);
970 PyModule_AddObject(m
, "Channel", (PyObject
*)&ChannelType
);
971 Py_INCREF(&OutputChannelType
);
972 PyModule_AddObject(m
, "OutputChannel", (PyObject
*)&OutputChannelType
);
973 Py_INCREF(&ScaleType
);
974 PyModule_AddObject(m
, "Scale", (PyObject
*)&ScaleType
);