2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2011 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
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, see <http://www.gnu.org/licenses/>.
27 #include "scripting.h"
31 // This is a workaround for what I consider a defect in pyconfig.h
33 #undef _POSIX_C_SOURCE
37 static gboolean engine_initialised
= FALSE
;
42 struct cbox_command_target
*target
;
46 PyCboxCallback_New(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
48 struct PyCboxCallback
*self
;
50 self
= (struct PyCboxCallback
*)type
->tp_alloc(type
, 0);
55 return (PyObject
*)self
;
59 PyCboxCallback_Init(struct PyCboxCallback
*self
, PyObject
*args
, PyObject
*kwds
)
61 PyObject
*cobj
= NULL
;
62 if (!PyArg_ParseTuple(args
, "O!:init", &PyCapsule_Type
, &cobj
))
65 self
->target
= PyCapsule_GetPointer(cobj
, NULL
);
69 static PyObject
*cbox_python_do_cmd_on(struct cbox_command_target
*ct
, PyObject
*self
, PyObject
*args
);
72 PyCboxCallback_Call(PyObject
*_self
, PyObject
*args
, PyObject
*kwds
)
74 struct PyCboxCallback
*self
= (struct PyCboxCallback
*)_self
;
76 return cbox_python_do_cmd_on(self
->target
, _self
, args
);
79 PyTypeObject CboxCallbackType
= {
80 PyVarObject_HEAD_INIT(NULL
, 0)
81 .tp_name
= "_cbox.Callback",
82 .tp_basicsize
= sizeof(struct PyCboxCallback
),
83 .tp_flags
= Py_TPFLAGS_DEFAULT
,
84 .tp_doc
= "Callback for feedback channel to Cbox C code",
85 .tp_init
= (initproc
)PyCboxCallback_Init
,
86 .tp_new
= PyCboxCallback_New
,
87 .tp_call
= PyCboxCallback_Call
90 static gboolean
set_error_from_python(GError
**error
)
92 PyObject
*ptype
= NULL
, *pvalue
= NULL
, *ptraceback
= NULL
;
93 PyErr_Fetch(&ptype
, &pvalue
, &ptraceback
);
94 PyObject
*ptypestr
= PyObject_Str(ptype
);
95 PyObject
*pvaluestr
= PyObject_Str(pvalue
);
96 PyObject
*ptypestr_unicode
= PyUnicode_AsUTF8String(ptypestr
);
97 PyObject
*pvaluestr_unicode
= PyUnicode_AsUTF8String(pvaluestr
);
98 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "%s: %s", PyBytes_AsString(ptypestr_unicode
), PyBytes_AsString(pvaluestr_unicode
));
99 Py_DECREF(pvaluestr_unicode
);
100 Py_DECREF(ptypestr_unicode
);
101 //g_error("%s:%s", PyString_AsString(ptypestr), PyString_AsString(pvaluestr));
103 Py_DECREF(pvaluestr
);
106 Py_XDECREF(ptraceback
);
110 static gboolean
bridge_to_python_callback(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, struct cbox_osc_command
*cmd
, GError
**error
)
112 PyObject
*callback
= ct
->user_data
;
114 int argc
= strlen(cmd
->arg_types
);
115 PyObject
*arg_values
= PyList_New(argc
);
116 for (int i
= 0; i
< argc
; i
++)
118 if (cmd
->arg_types
[i
] == 's')
120 PyList_SetItem(arg_values
, i
, PyUnicode_FromString(cmd
->arg_values
[i
]));
123 if (cmd
->arg_types
[i
] == 'o')
125 struct cbox_objhdr
*oh
= cmd
->arg_values
[i
];
127 cbox_uuid_tostring(&oh
->instance_uuid
, buf
);
128 PyList_SetItem(arg_values
, i
, PyUnicode_FromString(buf
));
131 if (cmd
->arg_types
[i
] == 'u')
133 struct cbox_uuid
*uuid
= cmd
->arg_values
[i
];
135 cbox_uuid_tostring(uuid
, buf
);
136 PyList_SetItem(arg_values
, i
, PyUnicode_FromString(buf
));
139 if (cmd
->arg_types
[i
] == 'i')
141 PyList_SetItem(arg_values
, i
, PyLong_FromLong(*(int *)cmd
->arg_values
[i
]));
144 if (cmd
->arg_types
[i
] == 'f')
146 PyList_SetItem(arg_values
, i
, PyFloat_FromDouble(*(double *)cmd
->arg_values
[i
]));
149 if (cmd
->arg_types
[i
] == 'b')
151 struct cbox_blob
*blob
= cmd
->arg_values
[i
];
152 PyList_SetItem(arg_values
, i
, PyByteArray_FromStringAndSize(blob
->data
, blob
->size
));
156 PyList_SetItem(arg_values
, i
, Py_None
);
160 struct PyCboxCallback
*fbcb
= NULL
;
162 PyObject
*args
= PyTuple_New(3);
163 PyTuple_SetItem(args
, 0, PyUnicode_FromString(cmd
->command
));
164 PyObject
*pyfb
= NULL
;
167 struct PyCboxCallback
*fbcb
= PyObject_New(struct PyCboxCallback
, &CboxCallbackType
);
169 pyfb
= (PyObject
*)fbcb
;
176 PyTuple_SetItem(args
, 1, pyfb
);
177 PyTuple_SetItem(args
, 2, arg_values
);
179 PyObject
*result
= PyObject_Call(callback
, args
, NULL
);
191 return set_error_from_python(error
);
194 static PyObject
*cbox_python_do_cmd_on(struct cbox_command_target
*ct
, PyObject
*self
, PyObject
*args
)
196 const char *command
= NULL
;
197 PyObject
*callback
= NULL
;
198 PyObject
*list
= NULL
;
199 if (!PyArg_ParseTuple(args
, "sOO!:do_cmd", &command
, &callback
, &PyList_Type
, &list
))
202 int len
= PyList_Size(list
);
203 void *extra
= malloc(len
* sizeof(double));
204 struct cbox_osc_command cmd
;
205 GError
*error
= NULL
;
206 char *arg_types
= malloc(len
+ 1);
207 void **arg_values
= malloc(2 * len
* sizeof(void *));
208 void **arg_extra
= &arg_values
[len
];
209 cmd
.command
= command
;
210 cmd
.arg_types
= arg_types
;
211 cmd
.arg_values
= arg_values
;
212 double *arg_space
= extra
;
213 gboolean free_blobs
= FALSE
;
214 for (int i
= 0; i
< len
; i
++)
216 cmd
.arg_values
[i
] = &arg_space
[i
];
217 PyObject
*value
= PyList_GetItem(list
, i
);
219 if (PyLong_Check(value
))
222 *(int *)arg_values
[i
] = PyLong_AsLong(value
);
225 if (PyFloat_Check(value
))
228 *(double *)arg_values
[i
] = PyFloat_AsDouble(value
);
231 if (PyUnicode_Check(value
))
233 PyObject
*utf8str
= PyUnicode_AsUTF8String(value
);
235 arg_extra
[i
] = utf8str
;
236 arg_values
[i
] = PyBytes_AsString(utf8str
);
239 if (PyByteArray_Check(value
))
241 const void *buf
= PyByteArray_AsString(value
);
242 ssize_t len
= PyByteArray_Size(value
);
246 // note: this is not really acquired, the blob is freed using free and not cbox_blob_destroy
247 struct cbox_blob
*blob
= cbox_blob_new_acquire_data((void *)buf
, len
);
249 arg_values
[i
] = blob
;
257 PyObject
*ob_type
= (PyObject
*)value
->ob_type
;
258 PyObject
*typename_unicode
= PyObject_Str(ob_type
);
259 PyObject
*typename_bytes
= PyUnicode_AsUTF8String(typename_unicode
);
260 PyObject
*exc
= PyErr_Format(PyExc_ValueError
, "Cannot decode Python type '%s' to execute '%s'", PyBytes_AsString(typename_bytes
), command
);
261 Py_DECREF(typename_bytes
);
262 Py_DECREF(typename_unicode
);
267 arg_types
[len
] = '\0';
269 struct cbox_command_target target
;
270 cbox_command_target_init(&target
, bridge_to_python_callback
, callback
);
272 // cbox_osc_command_dump(&cmd);
274 gboolean result
= ct
->process_cmd(ct
, callback
!= Py_None
? &target
: NULL
, &cmd
, &error
);
279 for (int i
= 0; i
< len
; i
++)
281 if (arg_types
[i
] == 'b')
283 if (arg_types
[i
] == 's')
284 Py_DECREF((PyObject
*)arg_extra
[i
]);
292 return PyErr_Format(PyExc_Exception
, "%s", error
? error
->message
: "Unknown error");
297 static PyObject
*cbox_python_do_cmd(PyObject
*self
, PyObject
*args
)
299 if (!engine_initialised
)
300 return PyErr_Format(PyExc_Exception
, "Engine not initialised");
301 return cbox_python_do_cmd_on(&app
.cmd_target
, self
, args
);
304 #if CALFBOX_AS_MODULE
306 #include "config-api.h"
308 #include "wavebank.h"
311 static gboolean audio_running
= FALSE
;
313 static PyObject
*cbox_python_init_engine(PyObject
*self
, PyObject
*args
)
315 const char *config_file
= NULL
;
316 if (!PyArg_ParseTuple(args
, "|z:init_engine", &config_file
))
318 if (engine_initialised
)
319 return PyErr_Format(PyExc_Exception
, "Engine already initialised");
322 app
.tarpool
= cbox_tarpool_new();
323 app
.document
= cbox_document_new();
324 app
.rt
= cbox_rt_new(app
.document
);
325 app
.engine
= cbox_engine_new(app
.document
, app
.rt
);
326 app
.rt
->engine
= app
.engine
;
327 cbox_config_init(config_file
);
328 cbox_wavebank_init();
329 engine_initialised
= 1;
335 static PyObject
*cbox_python_shutdown_engine(PyObject
*self
, PyObject
*args
)
337 if (!PyArg_ParseTuple(args
, ":shutdown_engine"))
339 if (!engine_initialised
)
340 return PyErr_Format(PyExc_Exception
, "Engine not initialised");
342 CBOX_DELETE(app
.engine
);
344 cbox_tarpool_destroy(app
.tarpool
);
345 cbox_document_destroy(app
.document
);
346 cbox_wavebank_close();
349 engine_initialised
= FALSE
;
355 static PyObject
*cbox_python_start_audio(PyObject
*self
, PyObject
*args
)
357 PyObject
*callback
= NULL
;
358 if (!PyArg_ParseTuple(args
, "|O:start_audio", &callback
))
360 if (!engine_initialised
)
361 return PyErr_Format(PyExc_Exception
, "Engine not initialised");
363 return PyErr_Format(PyExc_Exception
, "Audio already started");
365 struct cbox_open_params params
;
366 GError
*error
= NULL
;
368 struct cbox_command_target target
;
369 if (callback
&& callback
!= Py_None
)
370 cbox_command_target_init(&target
, bridge_to_python_callback
, callback
);
372 if (!cbox_io_init(&app
.io
, ¶ms
, (callback
&& callback
!= Py_None
) ? &target
: NULL
, &error
))
373 return PyErr_Format(PyExc_IOError
, "Cannot initialise sound I/O: %s", (error
&& error
->message
) ? error
->message
: "Unknown error");
375 const char *effect_preset_name
= cbox_config_get_string("master", "effect");
377 cbox_rt_set_io(app
.rt
, &app
.io
);
378 cbox_scene_new(app
.document
, app
.engine
);
379 cbox_rt_start(app
.rt
, (callback
&& callback
!= Py_None
) ? &target
: NULL
);
380 if (effect_preset_name
&& *effect_preset_name
)
382 app
.engine
->effect
= cbox_module_new_from_fx_preset(effect_preset_name
, app
.document
, app
.rt
, app
.engine
, &error
);
383 if (!app
.engine
->effect
)
384 return PyErr_Format(PyExc_IOError
, "Cannot load master effect preset %s: %s", effect_preset_name
, (error
&& error
->message
) ? error
->message
: "Unknown error");
386 audio_running
= TRUE
;
392 static PyObject
*cbox_python_start_noaudio(PyObject
*self
, PyObject
*args
)
394 PyObject
*callback
= NULL
;
396 if (!PyArg_ParseTuple(args
, "i|O:start_noaudio", &sample_rate
, &callback
))
398 if (!engine_initialised
)
399 return PyErr_Format(PyExc_Exception
, "Engine not initialised");
401 return PyErr_Format(PyExc_Exception
, "Audio already started");
403 struct cbox_command_target target
;
404 if (callback
&& callback
!= Py_None
)
405 cbox_command_target_init(&target
, bridge_to_python_callback
, callback
);
407 cbox_rt_set_offline(app
.rt
, sample_rate
, 1024);
408 cbox_scene_new(app
.document
, app
.engine
);
409 cbox_rt_start(app
.rt
, (callback
&& callback
!= Py_None
) ? &target
: NULL
);
410 audio_running
= TRUE
;
416 static PyObject
*cbox_python_stop_audio(PyObject
*self
, PyObject
*args
)
418 if (!PyArg_ParseTuple(args
, ":stop_audio"))
420 if (!engine_initialised
)
421 return PyErr_Format(PyExc_Exception
, "Engine not initialised");
423 return PyErr_Format(PyExc_Exception
, "Audio not running");
425 while(app
.engine
->scene_count
> 0)
426 CBOX_DELETE(app
.engine
->scenes
[0]);
427 cbox_rt_stop(app
.rt
);
428 cbox_io_close(&app
.io
);
429 audio_running
= FALSE
;
436 static PyMethodDef CboxMethods
[] = {
437 {"do_cmd", cbox_python_do_cmd
, METH_VARARGS
, "Execute a CalfBox command using a global path."},
438 #if CALFBOX_AS_MODULE
439 {"init_engine", cbox_python_init_engine
, METH_VARARGS
, "Initialise the CalfBox engine using optional config file."},
440 {"shutdown_engine", cbox_python_shutdown_engine
, METH_VARARGS
, "Shutdown the CalfBox engine."},
441 {"start_audio", cbox_python_start_audio
, METH_VARARGS
, "Start real-time audio processing using I/O settings from the current config."},
442 {"start_noaudio", cbox_python_start_noaudio
, METH_VARARGS
, "Start dummy audio processing using sample rate specified as argument."},
443 {"stop_audio", cbox_python_stop_audio
, METH_VARARGS
, "Stop real-time audio processing."},
445 {NULL
, NULL
, 0, NULL
}
448 static PyModuleDef CboxModule
= {
449 PyModuleDef_HEAD_INIT
, "_cbox", NULL
, -1, CboxMethods
,
450 NULL
, NULL
, NULL
, NULL
453 #if CALFBOX_AS_MODULE
458 PyObject
*m
= PyModule_Create(&CboxModule
);
461 Py_INCREF(&CboxCallbackType
);
462 if (PyType_Ready(&CboxCallbackType
) < 0)
464 PyModule_AddObject(m
, "Callback", (PyObject
*)&CboxCallbackType
);
474 PyObject
*m
= PyModule_Create(&CboxModule
);
475 PyModule_AddObject(m
, "Callback", (PyObject
*)&CboxCallbackType
);
479 void cbox_script_run(const char *name
)
481 FILE *fp
= fopen(name
, "rb");
484 g_warning("Cannot open script file '%s': %s", name
, strerror(errno
));
487 PyImport_AppendInittab("_cbox", &PyInit_cbox
);
489 if (PyType_Ready(&CboxCallbackType
) < 0)
491 g_warning("Cannot install the C callback type");
494 Py_INCREF(&CboxCallbackType
);
495 engine_initialised
= TRUE
;
497 if (PyRun_SimpleFile(fp
, name
) == 1)
499 GError
*error
= NULL
;
500 set_error_from_python(&error
);
501 cbox_print_error(error
);