From vision to architecture
Sonic Pi, From Vision to Architecture
According to the last product vision essay, Sonic Pi is a live coding music synthesizer that aims to provide a joyful use experience to its users by transforming codes into music fluently and assisting code-beginners to easily learn how to code. The focus of this essay shifts to an examination of Sonic Pi’s architecture. Let’s begin our journey by looking at Sonic Pi’s architectural style.
Architectural style
Sonic Pi can be thought of as a client-side desktop application in terms of functionality. Sonic Pi’s user interface encapsulates all of its functions, and this graphical user interface serves as the view in the model-view-controller (MVC) architecture. Sonic Pi employs the MVC model, which is a popular software architecture pattern. In addition to the view, MVC has two other important interconnected components in its structure, as shown in the diagram below: the model and the controller.
M(model) in MVC defines the essential component of a project and can be understood as data storage. V(view) displays the model’s representation and allows users to edit the data. C (controller) is the link between M and V, and it is in charge of data flow. It is also the structure’s brain, deciding how to handle input data. It responds to user actions in the view layer, handles data with logic, and communicates data changes to the model. The model object in the Sonic Pi environment can refer to the music project that the user is currently working on. As previously stated, the view object is Sonic Pi’s user interface. The backend server is known as the controller. The user communicates with Sonic Pi via the interactive elements on the user interface. The server monitors all actions and manipulates them using APIs from third-party libraries. The current music project’s data will be updated and then sent through the server to the user interface, where it will be displayed as either a music file or a log record.
Containers View
From the container perspective, Sonic Pi is relatively simple. According to the C4 model 2, Sonic Pi has only one container available: the desktop App. Sonic Pi is a lightweight music coding software, thus it doesn’t involve multi-platform data communications - a desktop App is enough. This means that the developers don’t need to develop containers such as databases, mobile apps, web applications, client and server end applications. Users, on the other hand can use every functionality that Sonic Pi provides from the app itself.
The Sonic Pi containers view is depicted in the figure below.
Component View
Following the description of the container view, we now zoom in to the component view, and the component view diagram of Sonic Pi is shown below:
The container Desktop Application contains two components: a graphic user interface (GUI) and a server. The GUI is written in C++ and built with the Qt framework. The GUI provides users with all visual interactive functionalities, such as clickable buttons, a code input box, and log display. The GUI is not responsible for compiling codes; instead, it calls on the backend server to do so. The server, which is written in Ruby, serves as the heart of Sonic Pi. It not only exists to execute the input codes, but also to link to external libraries in order to borrow additional functionalities. For example, Aubio 3 and wavefile. In addition to the libraries, the server sends tracked data to an environment known as SuperCollider 4. Sonic Pi is assisted by SuperCollider in completing the task of real-time audio synthesis and algorithmic composition.
Connector View
Connector bridges between components and containers for communication. Open Sound Control(OSC) is a protocol for real-time communication between applications and hardware in low latency and high accuracy, which plays the connector role between the components and containers in Sonic Pi. It overcomes the inherent obstacles of MIDI protocol by utilizing an open-ended, customizable model and enables communication between hardware easier. In addition, compatibility is also one of the advantages of OSC 5. OSC libraries are available in the most popular programming languages, which allows Sonic Pi users with different programming language tastes to easily write the code to send or receive messages to or from Sonic Pi without learning an extra programming language 6.
Development View
The development of Sonic Pi has several dependencies in common on all platforms, namely -
- Qt
- CMake
- Ruby
- Elixir
- For Linux, Jack and SuperCollider + SC3 Plugins are also needed. These external dependencies form the basis for the software to have a decent interface, parse and compile codes, and create music.
The main repository is divided into 5 directories:
- app: the source code and configure files that realizes all functionalities of Sonic Pi.
- bin: includes the environment setting for Sonic Pi and includes its graffiti.
- etc: includes documentation, tutorials, examples of Sonic Pi
- install: tools for building the msi
- prebuild: header files and library dynamic link libraries
The app directory is the most important directory since it contains all the source codes. The source code is then divided into three main parts: api, gui, and server. The api directory includes all the functions the server will eventually call when executing commands from the user. The gui directory contains the mainwindow.cpp which is a qt file that defines the display of the Sonic Pi interface. The server directory contains files written in Ruby language that works as a multi-thread task manager to make everything smooth and sound good.
A snapshot of the software architecture from the development level is shown below:
Run time view
In the run time view we will show how the components of Sonic Pi interacts with each other during runtime. The scenario we discuss about is the most commonly occurred interaction: user type music codes for Sonic Pi to play.
The process starts with the user typing codes in the GUI. The coding environment in the GUI of Sonic Pi is the main tool for user to produce music. After the user presses the “run” button, the GUI will invoke and send the code to the server to execute. If the code is correct in syntax, the server will send the data to the SuperCollider, where it will be produced into synthesized music. The music is feeded back to the server to play. And the server will also refresh the GUI, so that it can visualize the sound wave for the user to observe. Moreover, the server maintains an internal virtual clock that schedules each music element’s timing, as specified by the user. Because the GUI, server, and SuperCollider are very different components that are written in different language, the Open Sound Controller (OSC) is in place to handle communication between them. It is a binary format that can be parsed by all components.
A visualization of the Run time view is depicted below:
External Key Quality Attributes
Efficiency and Correctness
As mentioned in the Runtime View section, Sonic Pi uses the SuperCollider synthesis engine to produce sounds. It defines the synths and effects beforehand in a special kind of binary file called a synthdef. These built-in synthdefs significantly contribute to the efficiency of Sonic Pi since they are loaded up on boot and ready to be triggered. And the accurate scheduling of Supercollider guarantees the correctness of the output audio.
Usability and Simplicity
Sonic Pi provides a large sets of audio options. Using SuperCollider, different types of sounds such as drums, electric sounds, and guitar are defined in the header api_list.h and can be synthesized after compiling.
As an educational software, Sonic Pi’s design always guarantees that a child of 10 can easily use and understand it. The simplicity mainly lies in its GUI, in which users write codes and run them to produce sounds. The GUI is written in C++ and uses the Qt framework. It does not do any heavy lifting of running code or making sound but only communicates with the server, which provides a simplified user interface.
Internal Key Quality Attributes
Maintainability
The well-structured source code gains Sonic Pi a high maintainability. The core team provides a strict but open environment for potential contributors, as well as detailed guidelines for development. Contributors are encouraged to limit the number of different technologies/frameworks/languages used in the project where practical7, which provides it a more organized and less complex environment for maintaining.
Also, with an aim of making it an international software either for educational or artistic use, Sonic Pi has paid much effort in facilitating its translators. To help translators keep track of the software’s development, Weblate, an open-source web-based translation editor Weblate is used. Non-developers can translate easily through this tool.
Testability
Sonic Pi provides a short document to help potential contributors in testing. Since Sonic Pi does not have a database, the tests are relatively easier. And the high testability is obtained by well organized tests.
$ cd app/server/ruby/test
$ rake test
This command would run all the tests8, including chord test, ring test, allocator test and so on. Development or errors can be easily located with the help of these test suites.
API design principles applied
There are mainly three APIs offered by the Sonic Pi and they are designed for MIDI9 and Minecraft Pi10, and GUI API11 respectively. Minecraft Pi is a version of Minecraft deployed on the Raspberry Pi. This API allows you to combine the operations in Minecraft the music together to make Minecraft pi music videos. The MIDI API allows users to control the instruments like Synthesizers or keyboards. And the GUI API connects to the Ruby backend. Unfortunately, the Minecraft Pi has been removed from the latest Raspberry Pi OS but this API can still be employed in the older versions of Raspberry Pi OS. Regarding the API design, these APIs are application-specific and each API only serves a single application. In the interface of the API, due to the compactness of the API, there are only a few methods involved. Not too many interfaces are required and the size of the interface is small in each API. Because of the limitation of the range of each API, the reusability could play a less important role in the APIs. In addition, the naming of methods in the APIs is concise and clear. The users can easily get the gist of a method by checking the method name and the documentation without reading the source code. For instance, there is always an “mc_” prefix in front of the method in the API for Minecraft PI and the “mc_message” means sending a message in the game and “mc_set_block” represents setting a specific block in a specific location. The naming makes the interface explicit and the users can easily understand what it is for. And the methods can behave as expected. In this case, the information hiding is maximized and the surprise is minimized in this way. Clients can understand how to use this API quickly without too much effort.
Reference
-
https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html ↩︎
-
Simon Brown. (n.d.-a). The C4 model for visualising software architecture. Retrieved March 15, 2021, from https://c4model.com/ ↩︎
-
Aubio, a tool designed for the extraction of annotations from audio signals : https://aubio.org/ ↩︎
-
SuperCollider is a platform for audio synthesis and algorithmic composition: https://supercollider.github.io/ ↩︎
-
Center for Computer Research in Music and Acoustics. (2021). OSC index. OpenSoundControl. https://ccrma.stanford.edu/groups/osc/index.html ↩︎
-
Sonic Pi. (2022a). Sonic Pi - Tutorial. Sonic Pi Tutorial. https://sonic-pi.net/tutorial.html ↩︎
-
Sonic Pi Contribution Doc. https://github.com/sonic-pi-net/sonic-pi/blob/dev/CONTRIBUTING.md ↩︎
-
Sonic Pi Tests Doc. https://github.com/sonic-pi-net/sonic-pi/blob/dev/TESTING.md ↩︎
-
Sonic Pi. (2022b). Sonic Pi - Tutorial. Tutorial - Sonic Pi. https://sonic-pi.net/tutorial.html#section-11-2 ↩︎
-
Sonic Pi. (2021). sonic-pi/A.06-minecraft.md at dev · sonic-pi-net/sonic-pi. Sonic Pi - GitHub. https://github.com/sonic-pi-net/sonic-pi/blob/dev/etc/doc/tutorial/A.06-minecraft.md ↩︎
-
Sonic Pi. (2016). Sonic Pi Internals GUI Ruby API · sonic-pi-net/sonic-pi Wiki. Sonic Pi - GitHub. https://github.com/sonic-pi-net/sonic-pi/wiki/Sonic-Pi-Internals----GUI-Ruby-API ↩︎