Zynthian GUI start up walkthrou'
1 The Zynthian GUI start process
It's important to consider quite what makes up the components of the zynthian system, because it isn't just one big blob of code that does everything. It's divided up into components that handle specific areas of concern. There is the GUI application that runs the GUI Screen handling and as a result probably provides the component that a user may identify most closely as the Zynthian.
2 X-Windows
The GUI screen in whatever form you may access it, be that on a zynthian itself or via a connected HDMI screen, a raspberry Pi 7" touchscreen, a 2.5" LCD screen or over a VNC connection on a browser, is a X-Window device generated by the Python TKinter module. From the zynthians perspective it doesn't care it just handles a X-Windows window which provides the interface.
This means that implementing mice and cursor's into this world is fairly simple and so the GUI can use a mouse simply connected to the Pi's USB port. The Zynthian has a setting to turn a cursor on & off for precisely this reason. The touchscreen is implemented this ways as well. This means that there are various display settings that allow font size and horizontal & vertical screen size to be defined. To cope with this wide range of displays. This has the side effect that screen characteristics need to be considered,so we avoid the cutesy pictures that seem to proliferate on many dedicated hardware devices that have only one screen size to consider. . . ( This is probably a personal gripe...:-) but it's helps to understand this limitation when proposing new features that would require GUI alterations or additions.
3 SystemD
The starting point for any modern linux system is systemd and zynthian makes much use of thus infrastructure. Thus logging is best handled by using journalctl ( journalctl -fu zynthian will give a running report of service start up).
The entry point for the GUI that is managed by zynthian.service is the shell file
4 The Zynthian code entry point
4.1 zynthian.sh
/zynthian/zynthian-ui/zynthian.sh
4.1.1 Defines
This file defines a few functions
- load_config_env
Configs from: source "$ZYNTHIAN_CONFIG_DIR/zynthian_envars_extended.sh" source "$ZYNTHIAN_MY_DATA_DIR/midi-profiles/default.sh" source "$ZYNTHIAN_CONFIG_DIR/zynthian_custom_config.sh"
- backlight_on
- backlight_off
- screensaver_off
- raw_splash_zynthian
- raw_splash_zynthian_error
- splash_zynthian
- splash_zynthian_error
Now these are fairly low level functionality and try to helpfully display some information in case the GUI doesn't start for some reason, like machine IP address ( a well known bootstrap problem in that if you don't know the machine address how can you point a terminal at it to configure it with it's IP address...?). So that if your zynth doesnt start you can ssh into it to examine quite why start up has failed ( It's normally jackd whinging about something...:-) )
Once that load_config_env has loaded up all the environmental variables that hold the actual state of a zynthian. It's all in there and is used to define the context that the zynthian runs under. Quite how a specific environment file is exposed to this process depends on the config, so mechanisms like MIDI configs define these states depending on whether or not a user has defined their own specific MIDI configuration or indeed several. Zynthian is basically a device for starting and stopping jack instruments and interacting with the engines once they are running. The GUI controls those interactions.
4.1.2 Commands
So the lines in the zynthian.sh file that start up the python elements are :
splash_zynthian load_config_env
while true; do # Start Zynthian GUI & Synth Engine cd $ZYNTHIAN_UI_DIR ./zynthian_main.py status=$?
We then start up the python file zynthian_main.py
4.2 zynthian_main.py
This is a small file that acts as an entry point to the zyngui object that is the base of all gui zynthian objects.
4.2.1 imports
# Zynthian specific modules from zyngui import zynthian_gui_config from zyncoder.zyncore import lib_zyncore from zyngui.zynthian_gui import zynthian_gui from zyngui import zynthian_gui_keybinding
And then start up the zynth.
4.2.2 Starting
logging.info("STARTING ZYNTHIAN-UI ...") zynthian_gui_config.zyngui = zyngui = zynthian_gui() zyngui.create_screens() zyngui.run_start_thread()
The zynthian configuration data is imported as zyngui, zynthian_gui and zynthian_gui_config.zyngui. They are all the same global python object. You keep the number of globals down to an absolute minimum and restrict yourself to objects. zyngui as it will hence forth be known is the Global Python object that the Zynthians GUI hangs off.
5 Zynthian Objects
Zynthian Object | Object Definition File | Object Name |
---|---|---|
zyngui | zyngui.zynthian_gui | zynthian_gui |
Example | Example | Example |
Example | Example | Example |
5.1 zyngui
Defined in the module zyngui/zynthian_gui.py as zynthian_gui but used as the global variable zyngui.
Firstly, virtually the entire zynthian universe is imported in about the first one hundred lines defining 80 or so base python namespaces.
Everything from the zynseq to brightness_config including the links to the C libraries that actually do the work as lib_zyncore, the zynengine objects that wrap the audio and MIDI devices and the many components used by the GUI screen.
It also defines the threads that respond to the various events that occur within the GUI environment and the various devices connected to the zynthian like Keyboards both musical and QWERTY, mice and all manner of MIDI paraphernalia.
Then the zynthian_gui Object is defined.
5.1.1 Functions
5.1.1.1 create_screens
The zynautoconnector is started which establishes the jack client connection to the Jack Server that does all the actual audio and midi processing, and runs this in it's own thread and handles the locking to ensure components play nice.
The global references for the audio recorder, the mixer and the sequencer are instantiated from there modules
object | module | function |
---|---|---|
self.audio_recorder | zyngui/zynthian_audio_recorder | Audio Recorder |
self.zynmixer | zynthian_engine_audio_mixer | Mixer |
self.zynseq | zynlibs/zynseq | Sequencer |
A dictionary called screens is defined and this has string keys that points to the individually defined screen objects that display the appropriate screens is defined and the value of the dictionary si set to the instantiated object from the .zyngui modules.
# Create Core UI Screens self.screens['info'] = zynthian_gui_info() self.screens['splash'] = zynthian_gui_splash() self.screens['loading'] = zynthian_gui_loading() self.screens['confirm'] = zynthian_gui_confirm() ....
The main menu is set depending on the zynthian kit...
and the zynthian device manager is instantiated.
Then the threads and polling mechanisms are started .