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 channel_volume_write(self
->channel
, PyFloat_AsDouble(value
));
219 Channel_get_balance(ChannelObject
*self
, void *closure
)
221 return PyFloat_FromDouble(channel_balance_read(self
->channel
));
225 Channel_set_balance(ChannelObject
*self
, PyObject
*value
, void *closure
)
227 channel_balance_write(self
->channel
, PyFloat_AsDouble(value
));
232 Channel_get_mute(ChannelObject
*self
, void *closure
)
236 if (channel_is_muted(self
->channel
)) {
246 Channel_set_mute(ChannelObject
*self
, PyObject
*value
, void *closure
)
248 if (value
== Py_True
) {
249 channel_mute(self
->channel
);
251 channel_unmute(self
->channel
);
257 Channel_get_solo(ChannelObject
*self
, void *closure
)
261 if (channel_is_soloed(self
->channel
)) {
271 Channel_set_solo(ChannelObject
*self
, PyObject
*value
, void *closure
)
273 if (value
== Py_True
) {
274 channel_solo(self
->channel
);
276 channel_unsolo(self
->channel
);
282 Channel_get_meter(ChannelObject
*self
, void *closure
)
287 if (channel_is_stereo(self
->channel
)) {
288 result
= PyTuple_New(2);
289 channel_stereo_meter_read(self
->channel
, &left
, &right
);
290 PyTuple_SetItem(result
, 0, PyFloat_FromDouble(left
));
291 PyTuple_SetItem(result
, 1, PyFloat_FromDouble(right
));
293 result
= PyTuple_New(1);
294 channel_mono_meter_read(self
->channel
, &left
);
295 PyTuple_SetItem(result
, 0, PyFloat_FromDouble(left
));
301 Channel_get_abspeak(ChannelObject
*self
, void *closure
)
303 return PyFloat_FromDouble(channel_abspeak_read(self
->channel
));
307 Channel_set_abspeak(ChannelObject
*self
, PyObject
*value
, void *closure
)
309 if (value
!= Py_None
) {
310 fprintf(stderr
, "abspeak can only be reset (set to None)\n");
313 channel_abspeak_reset(self
->channel
);
318 Channel_set_midi_scale(ChannelObject
*self
, PyObject
*value
, void *closure
)
320 ScaleObject
*scale_object
= (ScaleObject
*)value
; /* XXX: check */
322 channel_set_midi_scale(self
->channel
, scale_object
->scale
);
328 Channel_get_midi_change_callback(ChannelObject
*self
, void *closure
)
330 if (self
->midi_change_callback
) {
331 Py_INCREF(self
->midi_change_callback
);
332 return self
->midi_change_callback
;
340 channel_midi_callback(void *userdata
)
342 ChannelObject
*self
= (ChannelObject
*)userdata
;
343 PyGILState_STATE gstate
;
345 gstate
= PyGILState_Ensure();
346 PyObject_CallObject(self
->midi_change_callback
, NULL
);
347 PyGILState_Release(gstate
);
351 Channel_set_midi_change_callback(ChannelObject
*self
, PyObject
*value
, void *closure
)
353 if (value
== Py_None
) {
354 self
->midi_change_callback
= NULL
;
355 channel_set_midi_change_callback(self
->channel
, NULL
, NULL
);
357 if (!PyCallable_Check(value
)) {
358 PyErr_SetString(PyExc_TypeError
, "value must be callable");
361 if (self
->midi_change_callback
) {
362 Py_XDECREF(self
->midi_change_callback
);
365 self
->midi_change_callback
= value
;
366 channel_set_midi_change_callback(self
->channel
,
367 channel_midi_callback
, self
);
374 Channel_get_name(ChannelObject
*self
, void *closure
)
376 return PyString_FromString(channel_get_name(self
->channel
));
380 Channel_set_name(ChannelObject
*self
, PyObject
*value
, void *closure
)
382 channel_rename(self
->channel
, PyString_AsString(value
));
387 Channel_get_balance_midi_cc(ChannelObject
*self
, void *closure
)
389 return PyInt_FromLong(channel_get_balance_midi_cc(self
->channel
));
393 Channel_set_balance_midi_cc(ChannelObject
*self
, PyObject
*value
, void *closure
)
398 new_cc
= PyInt_AsLong(value
);
399 result
= channel_set_balance_midi_cc(self
->channel
, new_cc
);
404 PyErr_SetString(PyExc_RuntimeError
, "value already in use");
405 } else if (result
== 2) {
406 PyErr_SetString(PyExc_RuntimeError
, "value out of range");
412 Channel_get_volume_midi_cc(ChannelObject
*self
, void *closure
)
414 return PyInt_FromLong(channel_get_volume_midi_cc(self
->channel
));
418 Channel_set_volume_midi_cc(ChannelObject
*self
, PyObject
*value
, void *closure
)
423 new_cc
= PyInt_AsLong(value
);
424 result
= channel_set_volume_midi_cc(self
->channel
, new_cc
);
429 PyErr_SetString(PyExc_RuntimeError
, "value already in use");
430 } else if (result
== 2) {
431 PyErr_SetString(PyExc_RuntimeError
, "value out of range");
436 static PyGetSetDef Channel_getseters
[] = {
438 (getter
)Channel_get_is_stereo
, NULL
,
439 "mono/stereo", NULL
},
441 (getter
)Channel_get_volume
, (setter
)Channel_set_volume
,
444 (getter
)Channel_get_balance
, (setter
)Channel_set_balance
,
447 (getter
)Channel_get_mute
, (setter
)Channel_set_mute
,
450 (getter
)Channel_get_solo
, (setter
)Channel_set_solo
,
453 (getter
)Channel_get_meter
, NULL
,
456 (getter
)Channel_get_abspeak
, (setter
)Channel_set_abspeak
,
459 NULL
, (setter
)Channel_set_midi_scale
,
461 {"midi_change_callback",
462 (getter
)Channel_get_midi_change_callback
,
463 (setter
)Channel_set_midi_change_callback
,
464 "midi change callback", NULL
},
466 (getter
)Channel_get_name
,
467 (setter
)Channel_set_name
,
470 (getter
)Channel_get_balance_midi_cc
,
471 (setter
)Channel_set_balance_midi_cc
,
472 "Balance MIDI CC", NULL
},
474 (getter
)Channel_get_volume_midi_cc
,
475 (setter
)Channel_set_volume_midi_cc
,
476 "Volume MIDI CC", NULL
},
481 Channel_remove(ChannelObject
*self
, PyObject
*args
)
483 if (! PyArg_ParseTuple(args
, "")) return NULL
;
484 remove_channel(self
->channel
);
490 Channel_autoset_midi_cc(ChannelObject
*self
, PyObject
*args
)
492 if (! PyArg_ParseTuple(args
, "")) return NULL
;
493 channel_autoset_midi_cc(self
->channel
);
498 static PyMethodDef channel_methods
[] = {
499 {"remove", (PyCFunction
)Channel_remove
, METH_VARARGS
, "Remove"},
500 {"autoset_midi_cc", (PyCFunction
)Channel_autoset_midi_cc
, METH_VARARGS
, "Autoset MIDI CC"},
504 static PyTypeObject ChannelType
= {
505 PyObject_HEAD_INIT(NULL
)
507 "jack_mixer_c.Channel", /*tp_name*/
508 sizeof(ChannelObject
), /*tp_basicsize*/
510 (destructor
)Channel_dealloc
, /*tp_dealloc*/
517 0, /*tp_as_sequence*/
525 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /*tp_flags*/
526 "Channel objects", /* tp_doc */
529 0, /* tp_richcompare */
530 0, /* tp_weaklistoffset */
533 channel_methods
, /* tp_methods */
535 Channel_getseters
, /* tp_getset */
538 0, /* tp_descr_get */
539 0, /* tp_descr_set */
540 0, /* tp_dictoffset */
541 (initproc
)Channel_init
, /* tp_init */
543 Channel_new
, /* tp_new */
547 Channel_New(jack_mixer_channel_t channel
)
550 self
= (ChannelObject
*)PyObject_NEW(ChannelObject
, &ChannelType
);
552 self
->channel
= channel
;
553 self
->midi_change_callback
= NULL
;
555 return (PyObject
*)self
;
558 /** Output Channel Type **/
562 PyObject
*midi_change_callback
;
563 jack_mixer_output_channel_t
*output_channel
;
564 } OutputChannelObject
;
567 OutputChannel_remove(OutputChannelObject
*self
, PyObject
*args
)
569 if (! PyArg_ParseTuple(args
, "")) return NULL
;
570 remove_output_channel(self
->output_channel
);
576 OutputChannel_set_solo(OutputChannelObject
*self
, PyObject
*args
)
581 if (! PyArg_ParseTuple(args
, "Ob", &channel
, &solo
)) return NULL
;
583 output_channel_set_solo(self
->output_channel
,
584 ((ChannelObject
*)channel
)->channel
,
592 OutputChannel_set_muted(OutputChannelObject
*self
, PyObject
*args
)
597 if (! PyArg_ParseTuple(args
, "Ob", &channel
, &muted
)) return NULL
;
599 output_channel_set_muted(self
->output_channel
,
600 ((ChannelObject
*)channel
)->channel
,
609 static PyMethodDef output_channel_methods
[] = {
610 {"remove", (PyCFunction
)OutputChannel_remove
, METH_VARARGS
, "Remove"},
611 {"set_solo", (PyCFunction
)OutputChannel_set_solo
, METH_VARARGS
, "Set a channel as solo"},
612 {"set_muted", (PyCFunction
)OutputChannel_set_muted
, METH_VARARGS
, "Set a channel as muted"},
616 static PyTypeObject OutputChannelType
= {
617 PyObject_HEAD_INIT(NULL
)
619 "jack_mixer_c.OutputChannel", /*tp_name*/
620 sizeof(OutputChannelObject
), /*tp_basicsize*/
629 0, /*tp_as_sequence*/
637 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /*tp_flags*/
638 "Output Channel objects", /* tp_doc */
641 0, /* tp_richcompare */
642 0, /* tp_weaklistoffset */
645 output_channel_methods
, /* tp_methods */
648 &ChannelType
, /* tp_base */
650 0, /* tp_descr_get */
651 0, /* tp_descr_set */
652 0, /* tp_dictoffset */
659 OutputChannel_New(jack_mixer_output_channel_t output_channel
)
661 OutputChannelObject
*self
;
662 self
= (OutputChannelObject
*)PyObject_NEW(OutputChannelObject
, &OutputChannelType
);
664 self
->midi_change_callback
= NULL
;
665 self
->output_channel
= output_channel
;
667 return (PyObject
*)self
;
675 PyObject
*main_mix_channel
;
680 Mixer_dealloc(MixerObject
*self
)
682 Py_XDECREF(self
->main_mix_channel
);
684 destroy(self
->mixer
);
685 self
->ob_type
->tp_free((PyObject
*)self
);
689 Mixer_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
693 self
= (MixerObject
*)type
->tp_alloc(type
, 0);
696 self
->main_mix_channel
= NULL
;
700 return (PyObject
*)self
;
704 Mixer_init(MixerObject
*self
, PyObject
*args
, PyObject
*kwds
)
706 static char *kwlist
[] = {"name", NULL
};
709 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "s", kwlist
, &name
))
712 self
->mixer
= create(name
);
713 if (self
->mixer
== NULL
) {
714 PyErr_SetString(PyExc_RuntimeError
,
715 "error creating mixer, probably jack is not running");
719 self
->main_mix_channel
= Channel_New(get_main_mix_channel(self
->mixer
));
724 static PyMemberDef Mixer_members
[] = {
725 {"main_mix_channel", T_OBJECT
, offsetof(MixerObject
, main_mix_channel
), 0, "main_mix_channel"},
730 Mixer_get_channels_count(MixerObject
*self
, void *closure
)
732 return PyInt_FromLong(get_channels_count(self
->mixer
));
736 Mixer_get_last_midi_channel(MixerObject
*self
, void *closure
)
738 return PyInt_FromLong(get_last_midi_channel(self
->mixer
));
742 static PyGetSetDef Mixer_getseters
[] = {
743 {"channels_count", (getter
)Mixer_get_channels_count
, NULL
,
744 "channels count", NULL
},
745 {"last_midi_channel", (getter
)Mixer_get_last_midi_channel
, NULL
,
746 "last midi channel", NULL
},
751 Mixer_add_channel(MixerObject
*self
, PyObject
*args
)
755 jack_mixer_channel_t channel
;
757 if (! PyArg_ParseTuple(args
, "sb", &name
, &stereo
)) return NULL
;
759 channel
= add_channel(self
->mixer
, name
, (bool)stereo
);
761 if (channel
== NULL
) {
762 PyErr_SetString(PyExc_RuntimeError
, "error adding channel");
766 return Channel_New(channel
);
770 Mixer_add_output_channel(MixerObject
*self
, PyObject
*args
)
775 jack_mixer_output_channel_t channel
;
777 if (! PyArg_ParseTuple(args
, "s|bb", &name
, &stereo
, &system
)) return NULL
;
779 channel
= add_output_channel(self
->mixer
, name
, (bool)stereo
, (bool)system
);
781 return OutputChannel_New(channel
);
785 static PyMethodDef Mixer_methods
[] = {
786 {"add_channel", (PyCFunction
)Mixer_add_channel
, METH_VARARGS
, "Add a new channel"},
787 {"add_output_channel", (PyCFunction
)Mixer_add_output_channel
, METH_VARARGS
, "Add a new output channel"},
788 // {"remove_channel", (PyCFunction)Mixer_remove_channel, METH_VARARGS, "Remove a channel"},
792 static PyTypeObject MixerType
= {
793 PyObject_HEAD_INIT(NULL
)
795 "jack_mixer_c.Mixer", /*tp_name*/
796 sizeof(MixerObject
), /*tp_basicsize*/
798 (destructor
)Mixer_dealloc
, /*tp_dealloc*/
805 0, /*tp_as_sequence*/
813 Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
, /*tp_flags*/
814 "Mixer objects", /* tp_doc */
817 0, /* tp_richcompare */
818 0, /* tp_weaklistoffset */
821 Mixer_methods
, /* tp_methods */
822 Mixer_members
, /* tp_members */
823 Mixer_getseters
, /* tp_getset */
826 0, /* tp_descr_get */
827 0, /* tp_descr_set */
828 0, /* tp_dictoffset */
829 (initproc
)Mixer_init
, /* tp_init */
831 Mixer_new
, /* tp_new */
835 static PyMethodDef jack_mixer_methods
[] = {
836 {NULL
} /* Sentinel */
841 PyMODINIT_FUNC
initjack_mixer_c(void)
845 if (PyType_Ready(&MixerType
) < 0)
847 if (PyType_Ready(&ChannelType
) < 0)
849 if (PyType_Ready(&OutputChannelType
) < 0)
851 if (PyType_Ready(&ScaleType
) < 0)
854 m
= Py_InitModule3("jack_mixer_c", jack_mixer_methods
, "Jack Mixer C Helper Module");
856 Py_INCREF(&MixerType
);
857 PyModule_AddObject(m
, "Mixer", (PyObject
*)&MixerType
);
858 Py_INCREF(&ChannelType
);
859 PyModule_AddObject(m
, "Channel", (PyObject
*)&ChannelType
);
860 Py_INCREF(&OutputChannelType
);
861 PyModule_AddObject(m
, "OutputChannel", (PyObject
*)&OutputChannelType
);
862 Py_INCREF(&ScaleType
);
863 PyModule_AddObject(m
, "Scale", (PyObject
*)&ScaleType
);