Second part of the making a simple MIDI synth LV2 plugin tutorial from the Programming Music Production LV2 Plugins From Scratch series is online now:

@sjaehn Thanks Sven. I now have my first working synth. It is nice to be able to play with it.
I just wish there were more conceptual explanations, because I really don't know what I did. Especially wrt.:
- that mapping stuff
- all the calculations

I very much feel like the whole thing has been built backwards. We spent a lot of time setting things up and then they fell into place without much explanation. For example we used the return value of adsr() all the time without knowing it.

@sjaehn Another way to teach this would be to:
1) Outline the problem you are trying to solve.
2) Explain how it could be solved.
3) Implement a solution.
4) Demonstrate that the problem has been solved.
I think that would be much easier to follow.

I guess you want to keep the videos are short as possible but I think the material is too dense for that. I wonder how many people followed along.

Congrats, you successfully let the ducks swim 😃 .

You felt like the whole thing has been built backwards? I would say it's something in between. It's prototyping.

If you try to solve a problem, then it's easier to divide the problem into smaller portions. This is what we did in Key::get(). Split it into a adsr envelope method, a wave generator (sin), and a velocity transformation function....


... You could either go step by step straight forward and directly define the adsr method and what's going on inside. Or you firstly declare the adsr header only. And think about its inside later. This is prototyping.

This way look a bit like moving backwards sometimes, but it's advantageous for larger projects.

@sjaehn Thanks :]
Part of my problem is that I didn't understand what ADSR was supposed to do. Sure we knew the method signature, but not the purpose. And what does Key::get() get? It was not obvious to me what these methods were supposed to do.

I showed the plugin and code on stream today and tried to understand where an issue comes from. There I noticed that I didn't even know where the Key objects come from or how many there are.

Maybe it's just my lack of C++ knowledge, not sure.

@murks OK, I didn't explain the purpose of ADSR. Maybe I'm too focused on electronic musicians who want to start programming. For them the purpose was clear before.

ADSR envelopes are put on top for each key. To softly fade in (A_ttack), softly go down (D_ecay) to a S_ustain level, and softly fade out (R_elease). Othewise you would only have on (1) or off (0). This would produce very nasty clicks.

adsr() simply returns the level of the envelope function for the actual time when a key is on.

@murks And last but not least. The next video will contain a lot of new information. As we will switch to C++11 and have to rewrite parts of the code.

Therefore I recommend to take breaks in the video. Go to the resources. There are often additional examples provided.

@sjaehn Thanks for the explanations Sven. I just saw that you put video 11 up.

I take breaks during the video all the time, otherwise I could never follow along. I'm typing things out rather than using your source files. So I had about hundred errors after video 10 rather than 0.

I also consider rewriting the synth in C, maybe it helps with understanding what is going on. In any case, I guess I will need to consult additional resources.

@murks The new video is already down as I missed to include one of the audio tracks. I'll re-upload it later.

@sjaehn I got it to compile fine, lv2_validate does not complain, yet it can't be initialised in Carla or Jalv. How do I debug this?

@sjaehn I think it's a difference in mySimpleSynth.ttl but I sure can't see it.

I think it's something inside the mySimpleSynth.ttl. But it's a bit surprising as lv2_validate (and lv2lint ?) doesn't complain.
I think that there is something missing behind rdf:value. Please check. Maybe you can upload you .ttl file too.

There is a typo. There should be NO colon after value.
So rdf:value instead of rdf:value:

@sjaehn Thanks, I totally didn't see that.
I'm afraid this is not the only issue, it still does not instantiate.

UI: None
JACK Name: mySimpleSynth
Sample rate: 48000 Hz
Block length: 512 frames
MIDI buffers: 32768 bytes

(jalv.gtk3:25762): Gdk-CRITICAL **: 12:30:41.178: gdk_monitor_get_refresh_rate: assertion 'GDK_IS_MONITOR (monitor)' failed
Comm buffers: 524288 bytes
Update rate: 30.0 Hz
Failed to instantiate plugin.

@sjaehn Oh, I think I found it. I accidentally re-declared m. Validating...

@sjaehn Yes, that was the problem.
I made a mistake in instantiate() and accidentally redeclaed m in the success case, so the local m was shadowing the out one, which thus remained null.

Thanks for your help.

@sjaehn I would expect the compiler to throw a warning about this. Compilers for other languages do that.

18 minute video, 2 1/2 hours to follow it, without going into the resources. I call that dense material. Still, looking forward to playing with the synth now. Thanks a lot for your work.

@murks Using plain C makes absolutely sense for audio programming. I'm also planning a video about this.

OK, Key::get() is not the most intuitive name. Maybe play or synth would be better. But I used or will use these symbols differently.

Key::get() simply synthesizes an audio signal from the sine wave, the MIDI velocity, and the ADSR envelope.

Defining the class Key is clear. But this doesn't create an object. Right. This was your point.

The object is declared in the video at 2:20 as a member of MySineSynth. And its only one object. So the synth we made is a Monosynth. The object key starts its life at 2:28 in the initializer of MySineSynth.

Sign in to participate in the conversation

Fosstodon is an English speaking Mastodon instance that is open to anyone who is interested in technology; particularly free & open source software.