Calicofx is headless by design, I.e, there is no UI tied to the DSP processing. The ability to control and configure plugins is provided by a web interface that spawns as another process. In other words, the User facing control ability and the DSP engine are architect-ed as a client and server process respectively.

Interface #
A websocket interface is intentionally chosen to enable web-ui to communicate with the core directly without any bridges.
Another important design consideration is to use JSON + ZMQ
ZMQ is used for following reasons
- Allows multiple clients to connect
- Abstracts the Protocol (can switch from ws://* to tcp://* easily)
- Enables multiple design patterns
Communication pattern #
Important design consideration is to be aware that multiple clients(a.k.a UIs) can be connected to the singleton instance of the core. Any changes made by a client should be broadcast to all the other clients.
For example, if one of the UI triggers a tuner, all the other UI instance should be forced to show the UI for tuner. This way we achieve uniformity.
Hence, by definition, we want 2 communication endpoints

Sync endpoint #
A synchronous endpoint that takes in request from the client and returns result synchronously. Think Adding a node, Deleting a node, Updating a parameter etc…
In ZMQ, this is achieved by REQ / REP design pattern
Subscription endpoint #
All the frontend UIs should be notified when some changes is triggered by a UI. Hence, there is another endpoint that follows a publisher-subscriber model where the server notifies all the “subscribed” clients of the change
In ZMQ, this is achieved by PUBSUB design pattern
Message #
ZMQ provides the communication between 2 process (a.k.a IPC), but the packet is structured to be a JSON structure. JSON is chosen as the message format due to its wide acceptance across all programming languages and flexibility
The generic message structure looks something like below
{
command: <SUPPORTED_CMD>,
payload: [
{"operation-1": "value"},
{"operation-2": "value"},
....
]
}
The response for each synchronous message will be as below
{
"result":"OK/NOK",
"response":[
{"resp-1": "val"}
...
]
}
For any Error, the response will be be in the format. This is common for all the supported commands
{
"result":"NOK",
"response":[
{"message": "<reason-for-failure"}
]
}
Following messages are supported
CALICOFX_ADD_NODE
#
Adding a node. Each node is a valid plugin. Currently, only lv2 plugins are supported. The payload message looks like below
{
command: 0, //a.k.a CALICOFX_ADD_NODE
payload: [
{"uri": "<plugin-uri>"},
]
}
As a result, on success, following response is sent back. Where the name would be the name of the plugin appended by 4 decimal number to make it unique for example gx_stereo_amp might be gx_stereo_amp_4241. This way, there is a flexibility to add another instance of the same plugin.
The host is expected to save this name and use it for any operation on this plugin
{
"result":"OK",
"response":[
{"name": "name-of-plugin_%4d"}
]
}
CALICOFX_UPDATE_PARAM
#
Update a control parameter of the plugin. This requires the plugin to be instantiated (i.e loaded).
The message looks like
{
command: 1, //a.k.a CALICOFX_UPDATE_PARAM
payload: [
{"name": "name-of-plugin_%4d"},
{"param": "<name-of-control-param>"},
{"val":0.0f}
]
}
CALICOFX_LINK
#
Link a port between 2 nodes, the source node should be of type “output” and the destination port must be “input”. The following message is expected
{
command: 2, //a.k.a CALICOFX_LINK
payload: [
{"src-node": "name-of-plugin_%4d"},
{"src-port": "port-name"},
{"dst-node": "name-of-plugin_%4d"},
{"dst-port": "port-name"}
]
}
CALICOFX_UNLINK
#
Unlink is opposite to CALICOFX_LINK and removes the link between 2 nodes. Following is the expected message
{
command: 3, //a.k.a CALICOFX_UNLINK
payload: [
{"src-node": "name-of-plugin_%4d"},
{"src-port": "port-name"},
{"dst-node": "name-of-plugin_%4d"},
{"dst-port": "port-name"}
]
}
CALICOFX_REMOVE_NODE
#
Remove a node from the patchbay. Expected message structure
{
command: 4, //a.k.a CALICOFX_REMOVE_NODE
payload: [
{"name": "name-of-plugin_%4d"},
]
}