brummer10 / guitarix

guitarix virtual versatile amplification for Jack/Linux
249 stars 26 forks source link

JSON-RPC questions #58

Open Rippert opened 3 years ago

Rippert commented 3 years ago

I was trying out your python example in your new GIST, and I had some questions.

I wanted to see how the RPC interface handled moving plugins from the pool to the rack, but the GUI locks up when I tried that. I know it works when you use the -G switch, but something in the python demo was blocking that.

What is the syntax to read out just the list of plugins in the rack, plugins in the pool and how to move from one to the other?

Is there a general documentation of the RPC commands?

Seems like the RPC stuff is pretty similar to OSC, using a socket server and client protocol with text messages going back and forth. Is there a reason you chose RPC over OSC?

Rippert commented 3 years ago

I did find the Documentation folder, and I will run Doygen on it as described. I see I also should have Graphviz installed, anything else I should have for the documentation to work?

Rippert commented 3 years ago

I found guitarix/trunk/src/gx_head/engine/jsonrpc.cpp

There is a get_rack_unit_order, Insert_rack_unitand remove_rack_unit, just need to decode what the parameters are.

There are also some things that refer to ladspa, does this include all built in plugins and external, and LV2?

I'll have to write a simple rpc client to test out some of these, unless you can recommend an existing one?

brummer10 commented 3 years ago

I was trying out your python example in your new GIST, and I had some questions.

I wanted to see how the RPC interface handled moving plugins from the pool to the rack, but the GUI locks up when I tried that. I know it works when you use the -G switch, but something in the python demo was blocking that.

There was a little bug in guitarix, which lead to a dead loop. This is fixed in the latest git.

What is the syntax to read out just the list of plugins in the rack, plugins in the pool and how to move from one to the other?

    sock.call("get_rack_unit_order", [0])
    units = sock.receive().result
    print("mono")
    for i in units:
        print(i)
    sock.call("get_rack_unit_order", [1])
    stereo_units = sock.receive().result
    print("stereo")
    for i in stereo_units:
        print(i)

Is there a general documentation of the RPC commands?

Not really, only the source code.

Seems like the RPC stuff is pretty similar to OSC, using a socket server and client protocol with text messages going back and forth. Is there a reason you chose RPC over OSC?

We use json for our config files so we use it for intercommunication as well. Mainly the socket communication was introduced for our web-frontend,

brummer10 commented 3 years ago

I did find the Documentation folder, and I will run Doygen on it as described. I see I also should have Graphviz installed, anything else I should have for the documentation to work?

No, but note that the documentation is very sparse.

brummer10 commented 3 years ago

I found guitarix/trunk/src/gx_head/engine/jsonrpc.cpp

There is a get_rack_unit_order, Insert_rack_unitand remove_rack_unit, just need to decode what the parameters are.

There are also some things that refer to ladspa, does this include all built in plugins and external, and LV2?

I'll have to write a simple rpc client to test out some of these, unless you can recommend an existing one?

The most complete client is guitarix itself, the code is in machine.cpp the class GxMachineRemote

Rippert commented 3 years ago

Thanks Hermann, found the code under machine.cpp and I've been playing with mods to your python example. I did get it to list all the available plugins, but not as pretty as your listings are.

What is the syntax to move a plugin from the pool to the rack and vice-versa?

brummer10 commented 3 years ago

insert the convolver before the phaser, 1 == stereo, 0 == mono rack) sock.notify("insert_rack_unit", ["jconv", "phaser", 1]) append the convolver to the stereo rack on last position sock.notify("insert_rack_unit", ["jconv", "", 1]) remove the convolver from the rack, 1 == stereo rack, 0 == mono rack) sock.notify("remove_rack_unit", ["jconv", 1])

Rippert commented 3 years ago

Oh, I was so close! I just didn't understand the 1 == stereo and 0 == mono part.

Thanks Hermann, this is very helpful for my latest hare-brained scheme!

Rippert commented 3 years ago

I got my node.js script to send and receive RPC message with Guitarix working and I noticed when I sent a "listen" ["all"] message I was constantly receiving these messages:

{"jsonrpc": "2.0","method": "set","params": ["hardlim.v1",0,"maxlevel.left",0,"maxlevel.right",0]}

More specifically, a "listen" ["param"] message gets them going.

Your python example script has an explicit filter for these in RpcSocket.receive, so I assume this is normal operation.

I assume this is the message that make the output and limiter meters work (wasn't actually plugged into anything to see them change).

I've actually been meaning to ask if it is possible to turn these off in the gui as they sometimes cause xruns at low buffer sizes. So let me ask more generally, would you be against having a command line option to disable these? If not, could you point me to where the code for them is that I would have to switch off?

I know that they, and the RPC messages aren't running when Guitarix is headless, but I would like to keep the GUI open to control things without the CPU overhead of the meters running.

Another, probably harder, question is can all animated meters, including plugin ui's, be turned off?

All of this should be separate from the tuner. If it's on, I want to see the animated display to be able to tune.

Rippert commented 3 years ago

Another possibility is an option to change the update rate of the meters. Slower updates should give less xruns, but possibly still be usable (0 Hz would be OFF).

Or - switch from meters to a set of "LEDs", one for input signal detected above a threshold and another for clipping, like you typically get on a power amp. Of course this would mean a GUI change, so beyond anything I could try to code myself at this point.

Rippert commented 3 years ago

I think I found the code to disable the meters in gx_main_window.cpp, I'll play with that and submit a pull request if I get something I think works.

For the JSON-RPC, I found the parameters maxlevel.on_off and hardlim.on_off, which do stop the meters, but there are couple of things that may be bugs:

1 - When you turn those two to off (or either one individually) the {"jsonrpc": "2.0","method": "set","params": ["hardlim.v1",0,"maxlevel.left",0,"maxlevel.right",0]} messages continue, but values stop changing.

2 - When maxlevel.on_off is set to 0, maxlevel.left and maxlevel.right both go to zero and stay there, but hardlim.v1 freezes at the value it had when turned off.

I've also found that it's not the RPC messages being sent out or the meters being on that causes xruns, it's the actual updating of the screen display. So if you minimize the window, or even open the rack and scroll the meters out of sight, the xruns stop (or at least reduce significantly). So I'm not sure that the meters being turned off will fix this, or if it's a gui thing about how the meters are displayed in the window. I'll open another issue if there seems to be more to this, and try to keep this one to RPC questions.

brummer10 commented 3 years ago

Yes, it's really unlikely that the RPC messages caused Xruns. They are queued and send at max every 20ms, so it's low traffic.

Rippert commented 3 years ago

I agree, but I still think that the messages should stop when the meters are turned off via the RPC switch. They are conveying no information when the meters are off, even if they are not really hurting anything.

brummer10 commented 3 years ago

Output parameter been registered in a map, (machine.cpp line 112), we then send the parameter every 60ms (machine.cpp line 2602). To stop the output we just need to remove the parameter from the list (gx_main_window.cpp line 2892/2893) to enable the output again, we just need to re-register them to the map (gx_main_window.cpp line 2886/2887) So implement a option to switch the meters output "off" would be easy, but in this case it shouldn't be done with the on_off switch. They need to be register/unregistered from the map. We do that because we want output parameters as stream, not only when the value change like with "normal" parameters.

Rippert commented 3 years ago

OK, I found the gx_main_window.cpp lines a couple days ago, and tried changing them to false in a code hack. That did stop both the meter updates in the gui and the messages in RPC.

I just started learning about streams in javascript, so I know what you mean by a map, but not how to unmap (at least through RPC) something. Is there an unmap RPC command? Probably not worth adding one just to save an insignificant bit of bandwidth.

brummer10 commented 3 years ago

No, there is not. We never see the necessary to disable the meters. Usually they run anyway on a low priority, and should interference with the audio thread. Your report of this issue is the first one noticed that there could be issues when they run.

Rippert commented 3 years ago

Well, I am trying to run things at really low latency, and on a Raspberry PI, which isn't the most powerful computer. I'm convinced that the GUI is causing some xruns under these conditions, and that it is the meters being visible in the gui that are a major contributor.

I have actually found a way to somewhat avoid this using cpu isolation. If the main realtime thread is on an isolated cpu, and the main non-realtime thread on a non-isolated cpu xruns reduce significantly, and the gui, including the meters, works well.

Interestingly, the realtime threads thrown up by the zita-convolver library don't seem to bother the non-isolated cpu, probably because they are primarily using the NEON co-processor on a raspberry pi.

I know I'm talking about a very niche application. Like I said, if I can come up with a pull request that seems helpful to all this, I'll send it your way. Other than that, just a lot of questions which I hope you don't mind.

brummer10 commented 3 years ago

You are welcome, and I enjoy as well so special requests, as they drive the app to become a better tool.

Rippert commented 3 years ago

OK, I have a question. I notice that when Guitarix is started with no-gui, the meter messages are off, but if you start a GUI only session with -G, the meter messages start. How does the GUI only session start the meter messages? They do not have IDs, so they are not responses to a call.

Rippert commented 3 years ago

Another question. I notice that it is possible to turn on more than one tube at a time via RPC, even though picking a tube on the GUI always turns the new tube on and the old tube off. What happens in terms of the signal chain when more than one tube is on at the same time, parallel tubes, serial tubes, undefined? I'm working remotely right now, so I can't hear what it sound like.

brummer10 commented 3 years ago

OK, I have a question. I notice that when Guitarix is started with no-gui, the meter messages are off, but if you start a GUI only session with -G, the meter messages start. How does the GUI only session start the meter messages? They do not have IDs, so they are not responses to a call.

As stated above, the GUI register the maxlevel parameters in the update_map (gx_main_window.cpp line 2886/2887), so when the GUI isn't started, they are not in the map, hence they are not send out to listeners.

brummer10 commented 3 years ago

Another question. I notice that it is possible to turn on more than one tube at a time via RPC, even though picking a tube on the GUI always turns the new tube on and the old tube off. What happens in terms of the signal chain when more than one tube is on at the same time, parallel tubes, serial tubes, undefined? I'm working remotely right now, so I can't hear what it sound like.

Tubes been of type ModuleSelectorFromList, this class replace a current plugin with a new selected. So I would say that it is unlikely that more then one selected tube type is active. (Activate a new one will switch off the old one) But if it indeed is possible with a RPC message by bypass the class, then they will run serial were the position of the new tube is undefined.

Rippert commented 3 years ago

I'm sorry for being stupid, but I don't understand.

If you start the engine with guitarix -N there are no maxlevel parameters in the update_map. Then you start the GUI seperately with guitarix -G, they only communicate through JSON-RPC messages, at least I thought so. Now there are maxlevel parameters in the update_map. So how does the GUI communicate the change of the update_map without sending a JSON-RPC message?

brummer10 commented 3 years ago

The update_map is part of machine (machine.cpp line 112). The machine (machine.cpp line 2600) send a request (every 60ms) to ask for the values of the paramters in the update_map. The engine didn't know about a update_list, but just send the values for the requested parameters. (jsonrpc.cpp line 1043)

Rippert commented 3 years ago

OK, I see it now. There is a get_updates method that goes out in a JSON-RPC notification message. I think I was confused by the maxlevel parameter coming in as a set method notification. Seemed like something should be getting "set" somewhere. I assume you use get_updates mostly for meters and indicators that are not actually settable by any control?

I know just enough about JSON-RPC to be dangerous!

brummer10 commented 3 years ago

Yes, it is mostly in use for output parameters but it could be used for any parameter.

Rippert commented 3 years ago

Did a test yesterday. Ran two guitarix -N instances on their own isolated cpu cores on an RPi 4 running 2.1 ms latency (jackd alsa options -r 96000 -p 64 -n 2). On a seperate RI 3, I ran two guitarix -G instances. Set the presets to high cpu usage options. Try brummer:vibe, brummer:conv, Sonnie_Tele:clean_delay_chorus, with every plugin turned on, for examples. Made sure both the main VU meters, the Hardlim meter and at least one multi-channel plugin with meters (Graphic eq, multichannel compressor, etc.) was visible. It worked just about perfectly. Only an occasional xrun when changing presets. This would crush the audio with xruns if I ran it on the same computer with the native gui.

So, some things you can count on - The sky is blue, The Earth is round and Hermann is right.

Rippert commented 3 years ago

Ok, now back to JSON-RPC questions.

What is the .pp property doing? Most are obvious like .position, .on_off etc., It's an integer representing an ENUM, so I was guessing maybe it was which plugin preset it was set to, but I can't see any output on the RPC monitor when I switch presets, other than the changes in the controls.

Also, what are the v_type, c_type, and d_flags? I have some guesses, but still not sure.

Rippert commented 3 years ago

OK, .pp "pre", "post". Still not sure what those refer to.

brummer10 commented 3 years ago

Yes, it indicate if the plugin run before or after the amp.

Rippert commented 3 years ago

Thank you. I finally went back to look at gx_engine.cpp, and it's pretty clear there what pre and post mean as well as where all the various builtins and plugins go in the chain. I realize that I should be able to find all answers in the code without asking, but there is a lot of code.