This Dezyne modelling example is Hans and Etienne Kuppens’s submission for the Dezyne Challenge 2018. The Dezyne Digital Orchestra is an example of Dezyne project that specifically satisfies the two points of particular interest that were announced in the Dezyne Challenge 2018 assignment: Concurrency and Internet of Things (IoT). Also this project fits in very well with the main hobby of the author, namely making music together. Making music is something that people do quite concurrently, and these people have to communicate and exchange information - just like with the IoT.
The Dezyne Digital Orchestra project consists of two independent applications: The Conductor and the Musician. Interesting fact: These applications have been developed independently by the two participants of the challenge.
The role of the Conductor is to read a song (midi file) from the file system, and to broadcast the midi notes to all Musicians that are connected to the Conductor. The Conductor determines the rhythm in which the song is played.
The role of a Musician is to connect to the Conductor and to play the received midi notes on the audio device. In the example project, each Musician plays all notes that are received but this could easily be extended such that a Musician applies a filter on the notes and only plays the instrument(s) that the Musician is capable of.
Note: The application allows that Musicians can freely hook on and hook off, also during the playing of a song. Only when all Musicians are hooked off, the Conductor stops conducting.
The structure of the Conductor is shown in the figure.
The upper (provided) port is where the GUI connects to the Dezyne system sConductor.
With commands from the GUI, the Conductor can start and stop serving, a midi file with the desired song can be selected, and the Conductor can start and stop conducting (playing) the song.
This provided port is connected to component cConductorApi, which serves as a guard against illegal calls.
On the bottom, two required ports are present. The first required port connects to cMidiReader, which is responsible for reading a midi file, and sending timed out events for each note that can be conducted. The other port connects to cSocketServer, which is responsible for sending the midi notes over a TCP/IP socket to all listeners.
The main component is cConductor, which controls the cMidiReader and cSocketServer components described above.
The structure of the Musician is similar, except that there is no separate guarding component immediately connected to the provided port; the GUI calls immediately enter the cMusician component. Another notable difference is that the cMusician interfaces directly to the external code that controls the midi sound device.
The cConductor component (which is by the way not the same as the cConductor in the Conductor application) provides the leanest interface to the cMusician, leaner than the cSocketClient component provides. The SocketClient is a component that is responsible for connecting to the Conductor and receive the TCP/IP messages containing the midi notes.
The code is generated in the Python language.
A nice demonstration of the project is presented in this video on youtube.
I do not have much programming experience, so it is difficult for me to compare Dezyne to anything else.
The tutorials were not very clear to me, these could be improved.
I found the responsiveness of the simulator a bit slow, I think the speed could be improved.
I am still very charmed by the methodology of Dezyne in all its aspects.
Some parts of the documentation can still be improved. For example:
It is not described how data parameters can be stored (temporarily) in a component, in case these need to be passed to another component at a later moment (not within the same event). After some trial and error (e.g. type redefinition) I finally succeeded.
Integrating code in the Python language.
I did not succeed to generate code for a "main" function for my model, as promised by the command "dzn code --help", despite the provided help of the Verum team.
Some other issues encountered:
When I select Help -→ check for updates, I do not get informed that a newer Dezyne version is available (I am currently using 2.4.0).
Code generation may silently fail, without error notification. I believe this is already a known issue.
Pressing F8 still generates C++ code by default, Dezyne does not remember that the project language is Python.
A verification error where the sequence diagram was incomplete.
In certain situations (I believe related to external requires) not all events are visible in the simulator (repeated events).
Tips and guidelines for others
For other users, the following tips/guidelines can reused from this project:
The handwritten components in conjunction with the cSocketClient and cSocketServer Dezyne components are a simple but useful example how to implement the TCP/IP socket client & server. The server supports multiple client connections. The limitation in the example implementation is that the send & receive calls are combined for all clients (each message is sent to all connected clients, and the received messages from all clients are merged).
An example "pattern" of Python code integration can be found in the project, i.e. in the classes hSocketServerApi, hSocketClientApi and hMidiReaderApi (implementing required handwritten components). Similarly, class sConductorProxy (in file Main.py) shows an example pattern how the provided interface of a Dezyne system could be embedded in a Python program.
The handwritten Python components (but this applies also for other programming languages) are truly multi-threaded, the project shows how easy it is to interface such code with the Dezyne single-threaded execution model.
You can download the example in a zip-file here.
Note that all of the diagrams included in this document have been produced in and exported from Dezyne. The System View and State Charts are part of the Dezyne editor. The Sequence Trace has been produced using the Dezyne simulation engine.