HexoSynth 2022 - Devlog #8 - A Visual DSP Programming Language
The HexoSynth modular synthesizer (programmed in Rust) got a visual DSP programming language, named WBlockDSP and it's first contribution from a contributor!
If you don't want to dig through the detailed log:
TLDR: Skip to the Devlog 8 Conclusion Section
Detailed Log
This is the day by day log of my progress. If this is too verbose for your interest, please skip down to the Devlog 8 Conclusion Section.
2022-08-03
HexoTK: Aside from publishing the previous devlog, I fixed a bug introduced by some
dependencies of HexoTK. winit
recently got an update, which broke some feature settings
in the dependency tree because my glutin
version was outdated. I successfully removed glutin
as one of HexoTK's dependencies now.
HexoTK: Fixed an annoying behavior with popups, where clicking somewhere else did not
just close the popup, but also activated something. Second I added PopupPos::MouseOffs
for specifying a small offset to open a context menu relative to the mouse cursor.
This helps with popups where the mouse cursor would be in the way after opening.
HexoDSP: As I'm more and more testing the WBlockDSP language directly from HexoSynth I started working on serializing the WBlockDSP state. So that I could reopen previous patches when testing. Only started working on it, I'm a bit too tired today to finish that.
2022-08-04
HexoDSP: WBlockDSP can now be serialized and deserialized properly. It's now part of the saveable HexoSynth patch. Still need to work on the automated tests though, to make sure this feature stays functional.
HexoDSP/synfx-dsp-jit: Worked on the WBlockDSP compiler more. Better error handling and fixed some bugs in synfx-dsp-jit and also in the compiler itself. More corner cases are covered now properly.
Devlog: Worked on the website a bit more. The embedded YouTube videos should be properly centered now and have a proper size too.
2022-08-05
HexoDSP/synfx-dsp-jit: Added a 'phase' node to synfx-dsp-jit and wrote a test for HexoDSP to cover an end-to-end test for audio output. The 'phase' node is a sawtooth oscillator that goes from 0.0 to 1.0. In the following demonstration you see me swapping out the input of the 'phase' node, which is the frequency of that oscillator in Hz.
HexoTK: Later I adjusted the size of the blocks of WBlockDSP a bit. So that there is enough space for a proper label like "phase".
HexoDSP/synfx-dsp: I've factored out a lot of the DSP code into it's own crate and uploaded a new crate to crates.io: synfx-dsp. All the generic DSP code I collected is now there. No framework, just plain little pieces of DSP code.
Then I refactored HexoDSP to use synfx-dsp.
synfx-dsp-jit: I've also refactored the CodeEngine
from hexodsp::wblockdsp
over to
synfx-dsp-jit and added an example that uses cpal to show off the JIT functionality:
https://github.com/WeirdConstructor/synfx-dsp-jit/blob/master/examples/cpal_jit_dsp.rs
// ...
loop {
engine.query_returns();
let freq = freqs[i];
i = (i + 1) % freqs.len();
engine
.upload(stmts(&[assign(
"&sig1",
op_mul(literal(0.3),
op_sub(
call("phase", 1, &[literal(freq)]),
literal(0.5))),
)]))
.expect("No compile error");
println!("{}", engine.get_debug_info());
std::thread::sleep(std::time::Duration::from_millis(300));
}
// ...
2022-08-06
Today I generally worked on merging the WBlockDSP development with the main branches of my repositories (HexoDSP, HexoTK, HexoSynth). I've also slightly improved the GUI situation with the WBlockDSP code editor, which can now be shown using the "Code" button at the top of the GUI.
synfx-dsp-jit: Implemented a shared buffer of atomic floats that can be read/written by the DSP thread while the controlling thread can do the same. With this the threads can exchange values without reuploading new DSP functions. See this example:
https://github.com/WeirdConstructor/synfx-dsp-jit/blob/master/examples/cpal_jit_dsp_atoms.rs
2022-08-07
synfx-dsp-jit: I can't leave synfx-dsp-jit
alone yet. First I wanted to implement
sample buffers that can be declared from the JIT AST itself. And second I wanted to
support uploading samples to the DSP function from outside. That is what I am working on
today.
2022-08-08
synfx-dsp-jit: The buffers and tables abstraction in the JIT has been mostly finished. Buffer sizes can now freely be declared at JIT compilation time and are updated in the real time thread on the fly. Tables have been changed too, their size can also vary now and they are generally read only. They are suitable for providing audio samples and other read only control data to the JIT function.
This effort does not directly benefit HexoSynth right now. But I know that at some point these features might eventually be added. And then is not the time to go back and make such deep changes to synfx-dsp-jit. And I also still have the faint hope, that someone might want to pick this up and build a different frontend for synfx-dsp-jit, something that is more like Reaktor or PureData / MaxMSP. And buffers and tables will be a quite central feature for that too.
HexoDSP/HexoSynth: I helped to day the first contributor to merge the FormFM
node.
A formant oscillator based on FM synthesis. Big thanks to Dimas Leenman! I took the
chance to enhance the "About" page styling a bit:
2022-08-09
HexoSynth Plugin: Today I worked on properly serializing the HexoSynth state. First tests looked very promising and I was able to store and load presets of HexoSynth patches in Renoise. Next I worked out a plan for external parameters from the DAW and how to handle MIDI properly. It will take some work and effort the next days to flesh those ideas out with some code.
HexoDSP: Later today I started actually writing code for handling MIDI notes. But it's still early concept code and not working at all yet.
YouTube Sound Demos
After the contribution of the FormFM node I noodled around a bit with it in HexoSynth. Nothing fancy, just a few scary and weird noises:
Devlog 8 Conclusion
First I want to welcome the first contributor Dimas Leenman who added the FormFM, a little FM synthesis node for formants. I took the chance to improve the HexoDSP documentation to support this and future contributions.
This week was devoted mostly to WBlockDSP, a little visual DSP programming language. The scope is, as earlier mentioned, a bit limited. And it is not a full blown general purpose programming language. But you can implement simple DSP algorithms with it. These little algorithms can be programmed and directly be used as DSP node/module from within HexoSynth.
At least that is the plan. I was not able to finish all the core features I wanted to it to have yet, and especially the UI side is still more a proof of concept than a finished user experience. But I wanted to have the core functionality done, and that was what I was able to achieve this week.
All this means, the road map point stabilize WBlockDSP
is crossed off my road map for now.
Even though there is still a lot of work to be done, I want to push forward and finish
the core workflow with HexoSynth first. The WBlockDSP language is really just a small and optional
part of the whole thing.
I also started with another point on the roadmap:
- Finish the nih-plug integration. That means a better integration of HexoSynth as VST3/CLAP plugin into your favorite DAW.
That means next I want to be able to send MIDI and audio to HexoSynth from within a DAW. Importing and Exporting presets already works mostly.
The following points remain on the roadmap towards the first release of HexoSynth in 2022:
- Add more automated test cases for the UI workflow.
- Rewrite the online help.
- Add inserting DSP chains that are to be pre-defined. And also inserting random DSP chains for a more explorative/experimental workflow.
- Add back editing CV widgets.
Contact
In case you find this project interesting or have questions,
you can reach me via Discord these days, check out the #hexosynth
channel
in the Rust Audio Discord. Optionally I'm also online
on IRC (via Matrix) in the Linux Audio Developer channel #lad
(nickname 'wct')
on Libera.Chat: irc:#lad@irc.libera.chat.