Re: [Cs-dev] Python Bindings Question
Date | 2008-02-26 09:23 |
From | victor |
Subject | Re: [Cs-dev] Python Bindings Question |
Attachments | None None |
Hello Greg,
The Python interface was mainly done by Michael
Gogins (well one might say it's done
by SWIG...). The message capture is, afaik, one of
the outstanding issues with
it. We need to somehow offer it as a Python
callback setter. The MIDI one probably
will follow the same line.
I have done something like that for the
CsoundPerformanceThread callback setter. Here
is the code (python_interface.i). This is SWIG
code:
1. first I create a typemap for it
// typemap for callbacks
%typemap(in) PyObject *pyfunc { if(!PyCallable_Check($input)){ PyErr_SetString(PyExc_TypeError, "Not a callable object!"); return NULL; } $1 = $input; } 2. Then I write the actual code to run/evaluate a
Python callback function (which
would be written and set by the user). Note that I
need to get the thread state
etc otherwise the Global Interpreter Lock (GIL)
will cause trouble:
%{
// this will be used as an interface to the // callback static void PythonCallback(void *p){ PyObject
*res;
CsoundPerformanceThread *t = (CsoundPerformanceThread *) p; if(t->_tstate == NULL) t->_tstate = PyThreadState_New(PyInterpreterState_New()); PyEval_AcquireThread(t->_tstate); res = PyEval_CallObject(t->pydata.func, t->pydata.data); if (res == NULL){ PyErr_SetString(PyExc_TypeError, "Exception in callback"); } else Py_DECREF(res); PyEval_ReleaseThread(t->_tstate); } %} 3. Then I make the interface ignore the original C++ callback setter.
%ignore CsoundPerformanceThread::SetProcessCallback(void (*Callback)(void *), void *cbdata); 4. Then I extend the CsoundPerformanceThread class to add in my
custom callback setter. Note that this function has different
arguments
to the original above (which makes it work in Python). It takes in
PyObjects, which is what Python passes around:
%extend CsoundPerformanceThread {
// Set the Python callback void SetProcessCallback(PyObject *pyfunc, PyObject *p){ if(self->GetProcessCallback() == NULL) { PyEval_InitThreads(); self->_tstate = NULL; } else Py_XDECREF(self->pydata.func); self->pydata.func = pyfunc; self->pydata.data = Py_BuildValue("(O)", p); self->SetProcessCallback(PythonCallback, (void *)self); Py_XINCREF(pyfunc); }
} Then it's done. The same principle can be used to customise/extend the
interface to
allow for the functions above to be called. The only thing that might cause
trouble is
the GIL shebang. What I do in the code is that for a new callback I call
PyEval_InitThreads()
to set/get thread states later. I suppose a similar thing can be tried,
when the callback
is set first time. We will need to find a place to store the thread state
variable, though.
If we use the Csound class and extend it in the python interface to have a
member
to do that, we might have our answer.
See what you think of the idea. I'll try to test a few things once I get a
break from
teaching.
Regards
Victor
|
Date | 2008-02-26 10:03 |
From | Greg Thompson |
Subject | Re: [Cs-dev] Python Bindings Question |
Attachments | None None |
Thanks Victor for your response. %ignore csoundSetCscoreCallback; %ignore csoundMessageV; %ignore csoundSetMessageCallback; %ignore csoundSetInputValueCallback; %ignore csoundSetOutputValueCallback; %ignore csoundSetExternalMidiInOpenCallback; %ignore csoundSetExternalMidiReadCallback; %ignore csoundSetExternalMidiInCloseCallback; %ignore csoundSetExternalMidiOutOpenCallback; %ignore csoundSetExternalMidiWriteCallback; %ignore csoundSetExternalMidiOutCloseCallback; %ignore csoundSetExternalMidiErrorStringCallback; %ignore csoundSetIsGraphable; %ignore csoundSetMakeGraphCallback; %ignore csoundSetDrawGraphCallback; %ignore csoundSetKillGraphCallback; %ignore csoundSetMakeXYinCallback; %ignore csoundSetReadXYinCallback; %ignore csoundSetKillXYinCallback; %ignore csoundSetExitGraphCallback; %ignore csoundSetYieldCallback; %ignore csoundSetPlayopenCallback; %ignore csoundSetRtplayCallback; %ignore csoundSetRecopenCallback; %ignore csoundSetRtrecordCallback; %ignore csoundSetRtcloseCallback; %ignore csoundRegisterSenseEventCallback; %ignore Csound::SetCscoreCallback; %ignore Csound::MessageV; %ignore Csound::SetMessageCallback; %ignore Csound::SetInputValueCallback; %ignore Csound::SetOutputValueCallback; %ignore Csound::SetExternalMidiInOpenCallback; %ignore Csound::SetExternalMidiReadCallback; %ignore Csound::SetExternalMidiInCloseCallback; %ignore Csound::SetExternalMidiOutOpenCallback; %ignore Csound::SetExternalMidiWriteCallback; %ignore Csound::SetExternalMidiOutCloseCallback; %ignore Csound::SetExternalMidiErrorStringCallback; %ignore Csound::SetIsGraphable; %ignore Csound::SetMakeGraphCallback; %ignore Csound::SetDrawGraphCallback; %ignore Csound::SetKillGraphCallback; %ignore Csound::SetMakeXYinCallback; %ignore Csound::SetReadXYinCallback; %ignore Csound::SetKillXYinCallback; %ignore Csound::SetExitGraphCallback; %ignore Csound::SetYieldCallback; %ignore Csound::SetPlayopenCallback; %ignore Csound::SetRtplayCallback; %ignore Csound::SetRecopenCallback; %ignore Csound::SetRtrecordCallback; %ignore Csound::SetRtcloseCallback; %ignore Csound::RegisterSenseEventCallback; %ignore CsoundPerformanceThreadMessage; %ignore CsPerfThread_PerformScore; greg On Feb 26, 2008, at 1:23 AM, victor wrote:
|