1 /*
2 * C S O U N D
3 *
4 * External language interfaces for the "C" and "C++" Csound API.
5 *
6 * L I C E N S E
7 *
8 * This software is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This software is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this software; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 */
22 
23 #ifndef MACOSX
24 %module(directors="1") csnd6
25 %feature("director") CsoundCallbackWrapper;
26 %feature("nodirector") Csound;
27 #else /* fix for OSX */
28 /* MODULE name is now csnd6 */
29 %module csnd6
30 #endif
31 %begin %{
32 #include <cmath>
33 %}
34 %include "typemaps.i"
35 %include "std_string.i"
36 %include "std_vector.i"
37 %include "carrays.i"
38 %array_functions(int, intp);
39 %array_functions(float, floatp);
40 %array_functions(double, doublep);
41 %array_class(int, intArray);
42 %array_class(float, floatArray);
43 %array_class(double, doubleArray)
44 
45 %begin %{
46 #ifdef _MSC_VER
47 #define SWIG_PYTHON_INTERPRETER_NO_DEBUG
48 #endif
49 %}
50 
51 %feature("autodoc", "1");
52 %{
53     #include <cmath>
54     #include <cstddef>
55     #include "csound.h"
56     #include "cfgvar.h"
57     #include "csound.hpp"
58     #include "cs_glue.hpp"
59     #include "csPerfThread.hpp"
60     #include "CsoundFile.hpp"
61     #include "CppSound.hpp"
62     #include "filebuilding.h"
63     #include "Soundfile.hpp"
64 %}
65 
66 %apply int { size_t };
67 typedef unsigned int uint32_t;
68 #ifndef MSVC
69 %apply long long { uint32_t };
70 #endif
71 
72 /* %typemap(in) char ** { */
73   /* Check if is a list */
74 /* if (PyList_Check($input)) {
75     int size = PyList_Size($input);
76     int i = 0;
77     $1 = (char **) malloc((size+1)*sizeof(char *));
78     for (i = 0; i < size; i++) {
79       PyObject *o = PyList_GetItem($input,i);
80       if (PyString_Check(o))
81         $1[i] = PyString_AsString(PyList_GetItem($input,i));
82       else {
83         PyErr_SetString(PyExc_TypeError,"list must contain strings");
84         free($1);
85         return NULL;
86       }
87     }
88     $1[i] = 0;
89   } else {
90     PyErr_SetString(PyExc_TypeError,"not a list");
91     return NULL;
92   }
93 }
94 
95 %typemap(freearg) char ** {
96   free((char *) $1);
97 } */
98 
99 %include "exclusions.i"
100 %ignore  csoundSetCscoreCallback(CSOUND *,void (*cscoreCallback_)(CSOUND *));
101 
102 // typemap for callbacks
103 %typemap(in) PyObject
104 
105 *pyfunc {
106   if($input != Py_None)
107   if(!PyCallable_Check($input)){
108     PyErr_SetString(PyExc_TypeError, "Not a callable object!");
109     return NULL;
110 }
111 $1 = $input;
112 }
113 
114 %{
115 // this will be used as an interface to the
116 // message callback
PythonMessageCallback(CSOUND * in,int attr,const char * format,va_list valist)117 static void PythonMessageCallback(CSOUND *in, int attr,
118                                      const char *format, va_list valist){
119 
120     PyObject *res;
121     Csound *p = (Csound *) csoundGetHostData(in);
122     pycbdata *pydata = (pycbdata *)p->pydata;
123     PyObject *pyfunc = pydata->mfunc, *arg;
124     char *mbuf = new char[sizeof(format)*10 + 256];
125     vsprintf(mbuf, format, valist);
126     //if(ch = strrchr(mbuf, '\n')) *ch = '\0';
127    if (strlen(mbuf) > 1){
128 #ifndef PYTHON_23_or_older
129        if(!PyEval_ThreadsInitialized())
130 #endif
131 	PyEval_InitThreads();
132     PyGILState_STATE gst;
133     // printf("MESS BEFORE \n");
134     gst = PyGILState_Ensure();
135     arg = Py_BuildValue("(s)", mbuf);
136     res =  PyEval_CallObject(pyfunc, arg);
137     if (res == NULL){
138        PyErr_SetString(PyExc_TypeError, "Exception in callback");
139     }else Py_DECREF(res);
140    // printf("Mes: %s \n", mbuf);
141    PyGILState_Release(gst);
142    // printf("MESS OVER \n");
143 }
144     delete[] mbuf;
145 }
VoidMessageCallback(CSOUND * in,int attr,const char * format,va_list valist)146 static void VoidMessageCallback(CSOUND *in, int attr,
147                                      const char *format, va_list valist){
148 //printf("void message callback\n");
149 }
150 
151 
PythonInChannelCallback(CSOUND * in,const char * chan,void * v,const void * channelType)152  static void PythonInChannelCallback(CSOUND *in, const char *chan, void *v,
153                                        const void *channelType){
154 
155     PyObject *res;
156     Csound *p = (Csound *) csoundGetHostData(in);
157     pycbdata *pydata = (pycbdata *)p->pydata;
158     PyObject *pyfunc = pydata->invalfunc, *arg;
159     PyGILState_STATE gst;
160     MYFLT *val = (MYFLT *) v;
161     gst = PyGILState_Ensure();
162     arg = Py_BuildValue("(s)", chan);
163     res =  PyEval_CallObject(pyfunc, arg);
164     if (res == NULL){
165        PyErr_SetString(PyExc_TypeError, "Exception in callback");
166     }else{
167       if(PyFloat_Check(res)) *val = (MYFLT) PyFloat_AsDouble(res);
168      else *val = 0.0;
169      Py_DECREF(res);
170     }
171    PyGILState_Release(gst);
172 
173 
174 }
175 
PythonOutChannelCallback(CSOUND * in,const char * chan,void * v,const void * channelType)176  static void PythonOutChannelCallback(CSOUND *in, const char *chan, void *v,
177                                                        const void *channelType) {
178 
179     PyObject *res;
180     Csound *p = (Csound *) csoundGetHostData(in);
181     pycbdata *pydata = (pycbdata *)p->pydata;
182     PyObject *pyfunc = pydata->outvalfunc, *arg;
183     PyGILState_STATE gst;
184     MYFLT *val = (MYFLT *) v;
185     gst = PyGILState_Ensure();
186     arg = Py_BuildValue("(s,d)", chan, (double) *val);
187     res =  PyEval_CallObject(pyfunc, arg);
188     if (res == NULL){
189        PyErr_SetString(PyExc_TypeError, "Exception in callback");
190     }else Py_DECREF(res);
191    PyGILState_Release(gst);
192 
193 }
194 
PythonMidiInOpen(CSOUND * in,void ** udata,const char * name)195 static int PythonMidiInOpen(CSOUND *in, void **udata, const char *name){
196 
197     PyObject *res;
198     Csound *p = (Csound *) csoundGetHostData(in);
199     pycbdata *pydata = (pycbdata *)p->pydata;
200     PyObject *pyfunc = pydata->midiinopenfunc, *arg;
201     PyGILState_STATE gst;
202     gst = PyGILState_Ensure();
203     arg = Py_BuildValue("(s)", name);
204     res =  PyEval_CallObject(pyfunc, arg);
205     if (res == NULL){
206        PyErr_SetString(PyExc_TypeError, "Exception in callback");
207     }else {
208        *udata = (void *) res;
209     }
210     PyGILState_Release(gst);
211     return 0;
212 }
213 
PythonMidiInClose(CSOUND * in,void * udata)214 static int PythonMidiInClose(CSOUND *in, void *udata){
215     PyObject *res;
216     Csound *p = (Csound *) csoundGetHostData(in);
217     pycbdata *pydata = (pycbdata *)p->pydata;
218     PyObject *pyfunc = pydata->midiinclosefunc, *arg;
219     PyGILState_STATE gst;
220     gst = PyGILState_Ensure();
221     arg = Py_BuildValue("(O)", (PyObject *) udata);
222     res =  PyEval_CallObject(pyfunc, arg);
223     if (res == NULL){
224        PyErr_SetString(PyExc_TypeError, "Exception in callback");
225     }else  Py_DECREF(res);
226     Py_DECREF((PyObject *) udata);
227     PyGILState_Release(gst);
228     return 0;
229 }
230 
PythonMidiRead(CSOUND * in,void * udata,unsigned char * buf,int nBytes)231 static int PythonMidiRead(CSOUND *in, void *udata,
232                                   unsigned char *buf, int nBytes){
233     PyObject *res;
234     int i;
235     Csound *p = (Csound *) csoundGetHostData(in);
236     pycbdata *pydata = (pycbdata *)p->pydata;
237     PyObject *pyfunc = pydata->midireadfunc, *arg;
238     PyGILState_STATE gst;
239     gst = PyGILState_Ensure();
240     arg = Py_BuildValue("(O,i)", (PyObject *) udata, nBytes);
241     res =  PyEval_CallObject(pyfunc, arg);
242     if (res == NULL){
243        PyErr_SetString(PyExc_TypeError, "Exception in callback");
244     }else {
245     if(PyList_Check(res))
246        for(i=0; i < nBytes; i++)
247           buf[i] = (char) PyInt_AsLong(PyList_GetItem(res,i));
248      else for(i=0; i < nBytes; i++)  buf[i] = 0;
249      Py_DECREF(res);
250      }
251     PyGILState_Release(gst);
252     return 0;
253 }
254 
pythonMessageCallback(CSOUND * csound,int attr,const char * format,va_list valist)255 static void pythonMessageCallback(CSOUND *csound,
256                                   int attr, const char *format, va_list valist)
257 {
258   char          buffer[8192];
259   static std::string  lineBuffer = "print '''";     // FIXME
260   unsigned int  i, len;
261 #ifdef HAVE_C99
262   len = (unsigned int) vsnprintf(&(buffer[0]), (size_t) 8192, format, valist);
263   if (len >= 8192U)
264     {
265       PyRun_SimpleString("print '''Error: message buffer overflow'''");
266       return;
267     }
268 #else
269   len = (unsigned int) vsprintf(&(buffer[0]), format, valist);
270   if (len >= 8192U)
271     {
272       PyRun_SimpleString("print '''Error: message buffer overflow'''");
273       exit(-1);
274     }
275 #endif
276   for (i = 0; i < len; i++) {
277     if (buffer[i] == '\n') {
278       lineBuffer += "'''";
279       PyRun_SimpleString(lineBuffer.c_str());
280       lineBuffer = "print '''";
281       continue;
282     }
283     if (buffer[i] == '\'' || buffer[i] == '\\')
284       lineBuffer += '\\';
285     lineBuffer += buffer[i];
286   }
287 }
288 
289 %}
290 
291 %ignore csoundSetHostData(CSOUND *, void *);
292 %ignore csoundGetHostData(CSOUND *);
293 %include "csound.h"
294 %include "cfgvar.h"
295 %apply MYFLT &OUTPUT { MYFLT &dflt, MYFLT &min, MYFLT &max };
296 %apply MYFLT &OUTPUT { MYFLT &value };
297 
298 
299 %ignore Csound::SetCscoreCallback(void (*cscoreCallback_)(CSOUND *));
300 %ignore Csound::SetOutputChannelCallback(channelCallback_t inputChannelCalback);
301 %ignore Csound::SetInputChannelCallback(channelCallback_t inputChannelCalback);
302 %ignore Csound::SetExternalMidiInOpenCallback(int (*)(CSOUND *, void *, const char*));
303 %ignore Csound::SetExternalMidiReadCallback(int (*)(CSOUND *, void *, unsigned char *, int));
304 %ignore Csound::SetExternalMidiInCloseCallback(int (*)(CSOUND *, void *));
305 
306 %ignore Csound::SetHostData(void *);
307 %ignore Csound::GetHostData();
308 %ignore Csound::SetMessageCallback(void (*)(CSOUND *, int attr,const char *format, va_list valist));
309 %include "csound.hpp"
310 
311 %extend Csound {
SetHostData(PyObject * data)312   void SetHostData(PyObject *data){
313    ((pycbdata *)self->pydata)->hostdata = data;
314 }
GetHostData()315   PyObject *GetHostData() {
316    return ((pycbdata *)self->pydata)->hostdata;
317 }
318   //#ifndef PYTHON_23_or_older
SetMessageCallback(PyObject * pyfunc)319   void SetMessageCallback(PyObject *pyfunc){
320      // thread safety mechanism
321     if (pyfunc == Py_None){
322        Py_XINCREF(pyfunc);
323        self->SetMessageCallback(VoidMessageCallback);
324        return;
325       }
326 
327     pycbdata *pydata = (pycbdata *) self->pydata;
328     if(pydata->mfunc == NULL) {
329         if(!PyEval_ThreadsInitialized())  PyEval_InitThreads();
330     }
331     else Py_XDECREF(pydata->mfunc);
332         pydata->mfunc = pyfunc;
333         self->SetMessageCallback(PythonMessageCallback);
334         Py_XINCREF(pyfunc);
335 }
336 
SetInputChannelCallback(PyObject * pyfunc)337    void SetInputChannelCallback(PyObject *pyfunc){
338      // thread safety mechanism
339     pycbdata *pydata = (pycbdata *) self->pydata;
340     if(pydata->invalfunc == NULL) {
341        if(!PyEval_ThreadsInitialized()) PyEval_InitThreads();
342     }
343     else Py_XDECREF(pydata->invalfunc);
344         pydata->invalfunc = pyfunc;
345         self->SetInputChannelCallback(PythonInChannelCallback);
346         Py_XINCREF(pyfunc);
347 	}
348 
SetOutputChannelCallback(PyObject * pyfunc)349    void SetOutputChannelCallback(PyObject *pyfunc){
350      // thread safety mechanism
351     pycbdata *pydata = (pycbdata *) self->pydata;
352     if(pydata->outvalfunc == NULL){
353       if(!PyEval_ThreadsInitialized()) PyEval_InitThreads();
354     }
355     else Py_XDECREF(pydata->outvalfunc);
356 
357         pydata->outvalfunc = pyfunc;
358         self->SetOutputChannelCallback(PythonOutChannelCallback);
359         Py_XINCREF(pyfunc);
360 }
SetExternalMidiInOpenCallback(PyObject * pyfunc)361 void SetExternalMidiInOpenCallback(PyObject *pyfunc){
362      // thread safety mechanism
363     pycbdata *pydata = (pycbdata *) self->pydata;
364     if(pydata->midiinopenfunc == NULL) {
365         if(!PyEval_ThreadsInitialized()) PyEval_InitThreads();
366     }
367     else Py_XDECREF(pydata->midiinopenfunc);
368         pydata->midiinopenfunc = pyfunc;
369         self->SetExternalMidiInOpenCallback(PythonMidiInOpen);
370         Py_XINCREF(pyfunc);
371 }
372 
SetExternalMidiInCloseCallback(PyObject * pyfunc)373 void SetExternalMidiInCloseCallback(PyObject *pyfunc){
374      // thread safety mechanism
375     pycbdata *pydata = (pycbdata *) self->pydata;
376     if(pydata->midiinclosefunc == NULL) {
377         if(!PyEval_ThreadsInitialized()) PyEval_InitThreads();
378     }
379     else Py_XDECREF(pydata->midiinclosefunc);
380         pydata->midiinopenfunc = pyfunc;
381         self->SetExternalMidiInCloseCallback(PythonMidiInClose);
382         Py_XINCREF(pyfunc);
383 }
384 
385 
SetExternalMidiReadCallback(PyObject * pyfunc)386 void SetExternalMidiReadCallback(PyObject *pyfunc){
387      // thread safety mechanism
388     pycbdata *pydata = (pycbdata *) self->pydata;
389     if(pydata->midireadfunc == NULL) {
390         if(!PyEval_ThreadsInitialized()) PyEval_InitThreads();
391     }
392     else Py_XDECREF(pydata->midireadfunc);
393         pydata->midiinopenfunc = pyfunc;
394         self->SetExternalMidiReadCallback(PythonMidiRead);
395         Py_XINCREF(pyfunc);
396 }
397 //#endif
398 }
399 
400 %clear MYFLT &dflt;
401 %clear MYFLT &min;
402 %clear MYFLT &max;
403 %clear MYFLT &value;
404 
405 
406 %{
407 // this will be used as an interface to the
408 // callback
PythonCallback(void * p)409 static void PythonCallback(void *p){
410 
411     PyObject *res;
412     PyGILState_STATE stat;
413     CsoundPerformanceThread *t = (CsoundPerformanceThread *) p;
414     stat = PyGILState_Ensure();
415     res = PyEval_CallObject(t->pydata.func, t->pydata.data);
416     if (res == NULL){
417     PyErr_SetString(PyExc_TypeError, "Exception in callback");
418      }
419     else Py_DECREF(res);
420     PyGILState_Release(stat);
421 }
422 %}
423 
424 
425 %ignore CsoundPerformanceThread::SetProcessCallback(void (*Callback)(void *), void *cbdata);
426 
427 %include "cs_glue.hpp"
428 %include "csPerfThread.hpp"
429 
430 %extend CsoundPerformanceThread {
431    // Set the Python callback
SetProcessCallback(PyObject * pyfunc,PyObject * p)432    void SetProcessCallback(PyObject *pyfunc, PyObject *p){
433     if(self->GetProcessCallback() == NULL) {
434 #ifndef PYTHON_23_or_older
435        if(!PyEval_ThreadsInitialized())
436 #endif
437                           PyEval_InitThreads();
438      }
439      else Py_XDECREF(self->pydata.func);
440     self->pydata.func = pyfunc;
441     self->pydata.data = Py_BuildValue("(O)", p);
442     self->SetProcessCallback(PythonCallback, (void *)self);
443     Py_XINCREF(pyfunc);
444 
445   }
446 
447 
448 }
449 
450 //#ifndef MACOSX
451 %include "CsoundFile.hpp"
452 //#endif
453 %include "CppSound.hpp"
454 /*
455 %include "filebuilding.h"
456 %include "Soundfile.hpp"
457 */
458 
459 
460 %extend CppSound {
setPythonMessageCallback()461   void setPythonMessageCallback()
462   {
463     self->SetMessageCallback(pythonMessageCallback);
464   }
465 
466 
467 };
468