Closed gogins closed 3 years ago
Investigate:
I think the playpen is quite doable using Python GTK from a decent code editor. The editor should have custom commands for:
This is all doable with a naming pattern (piece.py goes with piece.glade) and with standardized command line options for the piece, as I already have for Python pieces, but internalized in the piece itself.
Then there can be a template for the piece that loads the Glade file, interprets the command options, and has standard menus and windows in the piece.
It seems better to just write a playpen application using Python GTK.
Changed the design to be a Python GTK3 application, as that looks like it might well be cross-platform and everything I have tried has worked pretty well so far. I'm impressed by the cleanness of GTK. Outstanding tasks:
exec(piece_python, globals(), locals())
. In order to prevent the GUI from freezing, I have subclassed ctcsound.Csound as GtkCsound and overridden the perform method to use the Gtk event loop to run Csound with co-operative multiprocessing.User-specific settings should include:
In reality, the use of a naming convention to derive the output soundfile name means that none of the Csound settings are actually required, although I will keep the audio output device as a convenience. The audio input and MIDI settings I will not implement.
Post-processing tasks, which if any can be done with GStreamer? A glance shows GStreamer harder to implement than adapting my existing script.
For triggers, it may suffice to send 1 for the pressed
signal and 0
for the released
signal.
It may be cleaner to have different handlers for different signals, or for different widget classes.
GtkSourceView looks usable but also tricky. See https://stackoverflow.com/questions/10524196/load-gui-from-a-glade-with-gtksourceview-in-pygobject. I have to make Glade aware of SourceView like this https://cjenkins.wordpress.com/2012/05/08/use-gtksourceview-widget-in-glade/, but that didn't work. But adding the old directory for the catalog did work.
API is here: https://developer.gnome.org/gtksourceview/stable/.
Looks like I have to create the editor programmatically and swap it in for the current GtkTextView. No, I got Glade to use the GtkSource.View by adding its catalog directory.
Search and replace is now working but you always have to press enter in the search entry field to get stated, even if you are then going to replace that text. This is not quite standard.
My question is, considering that ctcsound.py comes with Csound, is there any way to get it into the WebKit JavaScript context without the C compiler?
My problem right now is that I don't really want to re-implement csound.node for WebKit2. My choices seem to be:
May need this: https://webkitgtk.org/reference/jsc-glib/stable/JSCContext.html.
OK, this is pretty bad. WebKit2Gtk+ deprecated webkit_frame_get_javascript_global_context
because the browser now uses GJS instead of JSC. There are now two APIs for JavaScript in WebKit, one from Apple and one from Gtk.
It's only a problem for me because SWIG uses the wrong API, which is not the one used by Gtk. It would be fine if I were writing a C/C++ program to use WebKit, but it is not fine if I am writing such a program to use WebKit2Gtk+.
I may have to code the wrappers by hand.
As a proof of concept... Jesus that was hard! Finally got "hello" to say "Hello from Csound!"
jsc_context_set_value (js_context,
"hello",
hello);
I am now trying to see if this machinery is accessible from Python, which would save me from packaging a native module. See https://gjs.guide/.
I can do this if and only if the GJS wrappers for Python implement registering a Python function as a JavaScript function and/or method in the Web page's JavaScript context.
https://github.com/cztomczak/cefpython is an option. It can introspect Python objects and dynamically create JavaScript bindings to classes and methods. Unfortunately it does not support Python later than version 3.7 on Linux.
There is a mad plethora of GUI frameworks, browser frameworks, and form builders for Python, not all of which work and none of which constitute a version-compatible set of libraries with all features that I need (compatible with ctcsound, embeddable form builder, full-featured browser that exposes ctcsound).
There's a hack for supporting cefpython3 on Python3.8 that works locally, just add the version number in init.py, and a symbolic link from the Python3.8 site-packages.
Now message.html plays from cefpython. But the GUI responsiveness gets turned off. I think I can deal with this by performing bufferwise and yielding to the event loop.
No, I can't get that to work. There are too many sharp edges with cefpython.
Of course there is no user guide for using GJS... Perhaps people just write native code and register it for GObject Introspection, I could try doing that with Csound.
Back with cefpython. Everything is working in Python and in CefPython using my new SWIG wrapper for CsoundThreaded.
Not everything is working! Getting messages to print for the user by polling the internal Csound message queue works fine in Python, but is not working in JavaScript. Although everything else is working in javaScript.
Print statement debugging shows everything is fine in CsoundThread right up until the number of messages pending is returned. Evidently it is properly returned from C++ to Python but not from Python to JavaScript.
Plan:
This installed pip for python3.7:
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
sudo python3.7 get-pip.py
sudo apt install libgirepository1.0-dev
sudo python3.7 -m pip install --ignore-installed PyGObject
Now I can run the Python stuff in the playpen with Python 3.7, but gtk3.py still segfaults.
My choices have now become:
OK, the method implementation works and the pattern is now clear.
Can't seem to get callbacks set from Python and called from JavaScript working. But I can try a workaround, the callback is actually not a callable but just the name of the callback and it is called simply by executing JavaScript code from the CsoundThread inner callback. Can't get this to work either, leaving the message callback unimplemented.
This is not a show-stopper, as the messages are printed in the terminal.
Removed the messages pane from the UI, leaving all messages printing to stdout and stderr.
I may come back to this.
Remaining issues before cleaning up:
Cleanup:
README.md
.README.md
.make install
target, I may add a Debian package or other installers later.Examples:
The XML parser will read the .glade file into memory and listen for value changes on control widgets, updating the XML in response. When saving, the .glade file will be written from the DOM and not from the .glade file previous read. This will work only if:
piece.ui.channels
file.The hard part is looking up elements from widgets. Some kind of extra metadata might simplify this. I can't arbitrarily add properties to the ui xml. But I could create a dictionary when I connect the signals.
The widget classes that I will save and restore, how their values can be accessed, and the xpath to the ui element that stores the value. This xpath begins at the element with the same id as the control channel name. "gk_channel" here stands for all channel names. For every get there is a corresponding set. Some of these are subclasses of others, but I need the specific class names in order to handle setting the values properly.
GtkButton
, event data parameter: not saved, but sent to channel.GtkCheckButton
, get_active
method, event data parameter.GtkEditable
, get_text
method.GtkRadioButton
, get_active
method, event data parameter.GtkScale
, get_value
method.GtkScaleButton
, get_value
method.GtkSpinButton
, get_value
method.GtkSwitch
, event data parameter, get_state
method.GtkToggleButton
, get_active
method.GtkVolumeButton
, get_value
method.There are three categories: the get_value
method, the get_active
method, and the get_text
method.
There is a fairly serious problem with the UI XML. Default widget values are not saved from ElementTree. I may be able to work around this, or I may use another method of storing the control channel values, e.g. with JSON for the map of channel names and values.
There are no Glade settings to control this, so ElementTree and GTK Builder are almost certainly not the problem.
I could work around this by constructing the elements for widget values in the XML, but I think I will go with a separate file, that should be less fragile.
I have a simple Python dict holding elementary type values for string channel names. This is saved and restored using JSON from piece.ui.channels
. It is a separate file and I hate that, but the solution is simple and should be robust.
I'm closing this now. I'm going to start using it. No doubt there will be bugs. They will become separate issues.
This is the old computer music playpen idea springing right back into life after my favorable experience with Python GTK used by python-abx.
The computer music playpen is an integrated development environment (IDE) for computer music that maximizes functionality and minimizes development time. The idea is to have the shortest, easiest "edit, render in real time and listen., edit..." cycle that is possible. Objectives:
Current approaches that implement some of this: