Csound Csound-dev Csound-tekno Search About

Re: [Cs-dev] Python Bindings Question

Date2008-02-26 09:23
Fromvictor
SubjectRe: [Cs-dev] Python Bindings Question
AttachmentsNone  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
----- Original Message -----
Sent: Tuesday, February 26, 2008 6:47 AM
Subject: [Cs-dev] Python Bindings Question

For a few days now, I've been asking around.  I'm wondering how to do the following using the python interface to Csound.  So far, I haven't been able to find anyone who knows the answer.  Is it even possible?  Maybe I should be asking that instead.

1 - how to capture stdout/stderr messages from the Csound instance

C API method
  PUBLIC void csoundSetMessageCallback(CSOUND *,
                            void (*csoundMessageCallback_)(CSOUND *,
                                                           int attr,
                                                           const char *format,
                                                           va_list valist));

2 - send midi events

C API method
  PUBLIC void csoundSetExternalMidiReadCallback(CSOUND *,
            int (*func)(CSOUND *, void *userData,
                                  unsigned char *buf, int nBytes));


3 - Is there a detailed manual on the python interface? 

thanks
greg


-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/


_______________________________________________
Csound-devel mailing list
Csound-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/csound-devel

Date2008-02-26 10:03
FromGreg Thompson
SubjectRe: [Cs-dev] Python Bindings Question
AttachmentsNone  None  
Thanks Victor for your response.

I finally stumbled upon exclusions.i which tells me what parts of the API are not enabled.  Essentially all of the callbacks which is understandable.

%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:

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
----- Original Message -----
Sent: Tuesday, February 26, 2008 6:47 AM
Subject: [Cs-dev] Python Bindings Question

For a few days now, I've been asking around.  I'm wondering how to do the following using the python interface to Csound.  So far, I haven't been able to find anyone who knows the answer.  Is it even possible?  Maybe I should be asking that instead.

1 - how to capture stdout/stderr messages from the Csound instance

C API method
  PUBLIC void csoundSetMessageCallback(CSOUND *,
                            void (*csoundMessageCallback_)(CSOUND *,
                                                           int attr,
                                                           const char *format,
                                                           va_list valist));

2 - send midi events

C API method
  PUBLIC void csoundSetExternalMidiReadCallback(CSOUND *,
            int (*func)(CSOUND *, void *userData,
                                  unsigned char *buf, int nBytes));


3 - Is there a detailed manual on the python interface? 

thanks
greg



-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/



_______________________________________________
Csound-devel mailing list
Csound-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/csound-devel
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
Csound-devel mailing list