Preparing a struct/struct member for float_4?

Hey :slight_smile:

Working on a synth, which is getting pretty cpu heavy and I think it’s time that I try to optimize it with float_4.

I’ve checked the tutorial(At the bottom):

Which shows how to make float_4 compatible variables, for single params, but since I am using some structs and struct members, it would be nice to see a basic example on how to prepare a struct/struct member for using float_4.

Can anyone point me to a module that does this, use a struct/struct member which is using float_4?

Thanks in advance!

They are vectors at heart.

1 Like

Probably most of the fundamental plugins? Many of my old Squinky Labs modules…

1 Like

I don’t have a direct answer to your question, but I’ve figured out a ton by cloning the entire VCV Rack Plugin Library repository (which includes ALL open source plugins’ source code as submodules) and global searching for things in there.

git clone https://github.com/VCVRack/library.git
cd library
git submodule update --init --recursive
1 Like
1 Like

Do they use structs outside of main?

I have some envelope and some oscillator structs outside of main.

Anyway, I’ll check your older modules, to see if I can find something I understand :slight_smile:

I think I probably should start with a simpler module, cause this one is getting a bit huge.

EDIT: Saw you example after I posted this, was answering from the top down. That doesn’t look too crazy.

I was really wondering if I had to make every single variable inside the struct float_4, which it looks like I do.

1 Like

Thanks, I should probably try to do that. I have downloaded a bunch from Github, but not all.

Well, I guess the truly accurate answer is that you need yo make everything a float4 that needs to be ;-). Like you could have some mono param or CV in there that only needs to get turned into a float4 as process time, so it depends. But I think you get the basic idea.

1 Like

Thanks!

Was just wondering if I had to do the [c/4] thing for each param inside the struct.

From what I understand, I need to rename the floats to float_4 inside the struct and make sure everything is compatible, and then do [c/4] when I call the struct in main.

But what do you think about other variables, like bool/int and so on, that does not use [c/4]? Won’t they get messed up, if i call the struct using [c/4]?

Here is a screenshot from the module:

Just want to add, I appreciate all you guys help a lot!

Once I have an optimised and “finished” it, I will release a version of it :slight_smile:

But this optimisation is kind of important, as it uses like 20% cpu on my M1 Macbook, when all 16 voice are playing :nauseated_face:

That’s a bit too much.

If I can just get it down to 1/2 or 1/3 of that, it would be lovely. That’s around the amount of cpu it uses when I build something similar with other modules.

But overall it’s a 3 operator full blown FM synth, with 16 voices polyphony. It has presets, which are only set pr. voice, so if you change preset, it will only change preset for the next voice and all the other poly voices before that, that might be playing, will still play the preset that was set for that poly voice, so it can make really cool and very complex sounds when you select a random presets on each trigger for each voice.

And lots of randomisation options, lots of probability and modulation, everything set pr. voice :slight_smile:

2 Likes

Short demonstration video:

There is 3 drums, kick, sd and hh from basic VCV modules and then all melody stuff is playing from the module. No effect or anything.

1 Like

Interesting project, and promising demo.

There are not any simd operations that work directly on user defined structures. They just operate on float_4, so if you want to make a call to “process” a structure, then you have to write the code to perform simd operations on the float_4 members within the struct. Also note there is a special simd::ifelse() method you need if you want to conditionally perform operations on individual members of a float_4 vector. So it may take a little while to get your bearings.

The Squinky Labs demo projects are an excellent resource for gaining an understanding. It is how I learned to use simd for my Venom plugin.

Are you doing true through-zero frequency modulation? Or are you doing phase modulation?

I recently finished my VCO Lab oscillator for the Venom v2.8 that I submitted to the library a couple days ago. Among many other things, it can do both TZFM and PM. I am really excited about what it can do. Now that I’ve completed my first oscillator, one of my ideas for a next oscillator to create is a 4 operator FM synth voice. So I am very interested to see what you come up with.

3 Likes

Thanks Dave :slight_smile:

Yeah I have a feeling it is not something easily done, especially not for a project like this, with multiple envelopes, oscillators, lfos, random and more and everything in separate structs.

I’ve made the envelopes that I use in this project as separate modules, I think I might try to make one of the to start with.

Do you think I can make a float_4 struct member?

Something like this:

struct Envelope{
               float_4 Env( bool trigger, float_4 pitch, float_4 Fm){
               // Envelope code here......
               }
}

And then call it from main:

Envelope[c/4].Env( gatein[c], parampitch[c/4], FmInput[c/4]);

I can see there might be an issue with the gatein, since it’s not float_4, but bool, so it would still use just [c]. Maybe I could just make that gatein float_4 too?

Envelope[c/4].Env( gatein[c/4], parampitch[c/4], FmInput[c/4]);

Yeah I need to look into that. That’s something I have been postponing for a while, since I feel it’s a bit of c++ voodoo. I also think it makes the code a bit harder to read, but should learn it so I can implement it from the start, so I don’t have to deal with doing it to everything at once in a huge project like this, cause it seems a bit daunting to do it now on everything.

I just add the fm like this:

frequency = (dsp::FREQ_C4 * std::pow(2.f, ParamFrequency + VoltInput  )) + FmInput;

Not sure what it is, I just played around until I had something working. It seems like it might be phase modulation?

And the feedback like this:

sine = sinf(2.f * M_PI * phase + feedback );

Sounds really cool. Will check your modules, just installed them :wink:

Once I get it optimised, I think I’ll add a 4th operator too. And nore goodies.

And also I’d like to add more osc options. Right now it’s just a sine, but would be nice to add some harmonics based versions of different oscillator shapes. Something like these shapes:

Screenshot 2024-06-28 at 21.34.23

Screenshot 2024-06-28 at 21.34.31

Screenshot 2024-06-28 at 21.34.37

Etc…

… Which are the shapes of the Elektron Digitones oscillators. I have all of them emulated in Pure Data, so I “just” need to figure out how to implement them in VCV, with decent interpolation. But yeah, it’s a lot of work to “just” do that.

I encourage you to not hesitate. The source code for the Squinky Labs plugin is brutal because the logic is spread out across so many damn files. But the demo project source code is nicely consolidated and relatively easy to follow, with nice explanatory text to go with it.

Interesting - looks like a hybrid. The first FM code looks like true frequency modulation, though I am surprised the FmInput does not have a scaling factor (unless that has already been precomputed). The feedback is doing phase modulation.

My background is more C than C++, with my hardcore C programming from 20+ years ago. With C++ I feel like I am constantly skating on thin ice - I am sure there are some fundamental concepts that I am missing or confused about. So I don’t feel qualified to provide advice on how to structure your code.

Yeah should probably just do it. Problem is, thart I am not super good at reading other peoples code, so I often just swing my own, in some way :laughing:

But for some things, there is really no way around it, like this, float_4

Will check the demo project :wink:

I do have a scaling factor, the FMinput is really FmInput*1000.f, but removed it for simplicity for this example… But might change it later, but it seems to work decent with 1000.

I started with the Axoloti board years ago, first when it came out. That was my introduction to coding, so it was kind of a steep learning curve. And then went on top Pure Data and finally ended in VCV. I really like VCV, though it can be pretty cpu intensive, but the pr. sample operation is really what appeals to me.

I really hated VCV when I had a subpar computer :sweat_smile:

But now that I have an M1 Macbook 2020, that can run it decently I love it :sunglasses:

Still running it via Rosetta, VCV2 2.4.1, but performance is still pretty good. I should probably update and convert my modules so they are Arm native, that coiuld probably also give a little bit better performance. I remember trying out some patches in Pure Data and comparing them and on bigger project I saw like 5-10% better performance using Native PD, instead of via Rosetta.

I’ve only dabbled with c++, I think, so that’s all I know, so not sure how it compares to other languages. All I know is that c++ is very powerful, but yeah, it can be kind of complicated learning stuff. But the more I learn, the easier it gets.

I did make some. modules for VCV1 too, so this is my second time around and I feel it goes a lot smoother this time around :wink:

Unlike my real code, the demo repo is super easy to understand. It’s quite generic.

I’ve hear the arm native boost is significant. @LarsBjerregaard ?

Yeah should probably do the switch over soon, might as well make the most of what we have :slight_smile:

Anecdotally in the ballpark of 15%

2 Likes

That sounds about right. Noticeable, but not amazing