Hello Gustav,
After giving it more thought, I think you are right. Given the current implementation of programs, doing anything here would be equivalent to assigning a big responsibility to the host that may have unforeseen consequences later. Also saving and loading parameters is easily enough done with any high level language that can talk gRPC so I’ll probably end up doing my own implementation of program creation and recovery for my use case.
But as you may start to know me a little now, I always have a couple of other unexpected things to report:
1 - Small bug in AudioRoutingController
The gRPC method DisconnectAllInputsFromTrack() will not actually disconnect all inputs from a track, but only the first input found.
You can reproduce this with elk-py (sorry I am not great at python, but this is a very simple demo)
This was tested with sushi -r -c ~/config_files/empty.json
#!/usr/bin/env python3
import asyncio
from elkpy import sushicontroller as sc
async def main():
controller = sc.SushiController()
await asyncio.sleep(0.5)
# Get tracks
tracks = controller.audio_graph.get_all_tracks()
# List all inputs of first track found
inputs = controller.audio_routing.get_input_connections_for_track(tracks[0].id)
print("inputs before deleting all : ", inputs)
# Clear all inputs of track
try:
ev = controller.audio_routing.disconnect_all_inputs_from_track(tracks[0].id)
print("cmd id:", ev.id)
res = await ev.wait()
except Exception as e:
print("Error disconnect_all_inputs_from_track")
# re-list all inputs of track for verification
inputs = controller.audio_routing.get_input_connections_for_track(tracks[0].id)
print("inputs after deleting all (should be empty) : ", inputs)
# should print an empty list, but return value is not empty.
asyncio.run(main())
And this is the result with the non-empty list :
ELKPY: Compiled proto found!
ELKPY: Sushi API match! -> 1.2.0
ELKPY: Asyncio context detected.
inputs before deleting all : [{
track: 0
track_channel: 0
engine_channel: 0
}, {
track: 0
track_channel: 1
engine_channel: 1
}]
cmd id: 3
inputs after deleting all (should be empty) : [{
track: 0
track_channel: 1
engine_channel: 1
}]
Curiously, the disconnect_all_outputs_from_track() counterpart is working fine in that regard.
2 - SessionController seems to skip saving and reloading properties set with elk-plugin-extensions.
This one is a bit more painful for me because I always have to redo a manual input of soundfont path in JuicySFplugin.
It’s even easier to test if you have sushi-gui available
Just create manually the processor on the track using those args:
{
"path" : "/opt/plugins/vst3/juicysfplugin.vst3",
"name" : "test",
"type" : "vst3x",
"uid" : "juicysfplugin"
},
add the property path via UI (this must match an actual soundfont path somewhere on the disk)

Save and reload session. Now property is gone:

Sushi stderr will also complain about it:
fluidsynth: error: No SoundFont with id = -1
fluidsynth: error: There is no preset with bank number 0 and preset number 0 in SoundFont -1
This one also feels really tricky. I could do manual detection / restore of properties that were set that way. But there is close to no documentation about how elk-plugin-extensions and ParameterController.SetPropertyValue() do work together. Also, as far as I know SetPropertyValue does not return an AsyncCommandResponse so any attempt to handle automatic property restoring would be brittle since there would be no way to know about the underlying task success / completion state. This is why I kinda expected SessionController to handle this as I understand that it manages asynchronous jobs better. But I may be wrong there too.