This project has moved and is read-only. For the latest updates, please go here.

Beginner to VST developing a Synth

Mar 1, 2011 at 4:07 AM

Hello,

 

For my senior project for Computer Science at my university, I chose to create a synthesizer. After fiddling with Xcode to no avail, I have adopted your framework which I discovered after searching for a way to create VST plug-ins through Visual Studio without delving into C++ (which I have no experience with and do not, at this time, have time to learn). I am mostly fluent in C# and VB.NET, so I thought that this would be a good place to start. I am also an electronic musician and have a lot of experience using both effect and plug-ins in Ableton Live 8. My project is simple - I will have a 10-harmonic slide control that will change timbre of the sound, and I will have an ADSR envelope controlled by knobs that will be put on the sound. I will have a master level control that will control the volume of the overall sound. I would like to have a graph showing the linear model of the ADSR envelope, but this is a stretch goal. Ideally, I will also have an LFO that will perform modular synthesis, but at this point in my progress, that is a stretch goal, as well. The plug-in will read in MIDI input from a keyboard, put the ADSR envelope on it, and perform the additive synthesis to add the timbre. Ideally, it seems that the MIDI input would simply provide a frequency and then the harmonics would be added to whatever frequency the MIDI input provided, but I'm not sure if that is the best way to do it yet. Anyway, not a concern for this forum.

I have read through the forum and know that you are not an expert on DSP, but I am having trouble understanding how all of the files/interfaces would fit together / be implemented for a VSTi. Is there any way you could show me how I could/should mock up the skeleton for such a project? I looked through the Samples that you provided, but I am not sure which one of them (if any)would suit my needs. If not, is there somewhere that you can point me where you feel that I could gain some understanding and/or begin to develop a solution for this project?

I appreciate any help you can provide in advance, and if there is any more information that I can provide to you to clarify or aid in your answer, please let me know.

 

Thanks,

Jake K.

Mar 1, 2011 at 6:40 AM

Hi Jake,

For the DSP part you're on your own. VST.NET does nothing for you there (but I think you know that ;-).

If I understand correctly, you intend to create a VSTi (a plugin that accepts Midi -in- and produces audio -out-). Perhaps the MidiNoteSampler sample is closest to what you intent to do. Although this sample also uses an audio input to record from - in playback mode it is in fact a VSTi (although a very simple one ;-). In short the MidiNoteSampler sample plugin records audio when a Midi note-on is detected for the first time- for the duration of the note (untill note-off). When that same note is played again, the recorded sample is played back on the audio outputs.

So my suggestion would be to take the MidiNoteSampler plugin and remove the code that records and plays back the samples and substitute it with a random generator (for now - or the simplest way of generating some audio you know of) that fires when the plugin receives midi note-on and note-off events. You can the go right ahead an try to load it into Ableton to see if you've got the VST stuff correct. After that you can focus on the DSP parts. If you need parameters for your plugin refer to the Delay sample.

Also note that VST.NET now has VS2008/VS2010 project and item templates that will get you started very quickly (from scratch). The project templates compile into working skeleton plugins. You could also start with the Midi project template and keep the source code of the MidiNoteSampler plugin sample as a reference.

Hope it helps,
Marc

Mar 16, 2011 at 11:26 PM
Edited Mar 17, 2011 at 3:11 AM

Hi Marc,

I am not sure how to connect a control on the UI to a parameter, modifying the value of the parameter when I change the value of the control. This seems very simple, but I am not sure how to do it. Can you point me in the right direction?

For example, I have a slider on my UI. I want this slider to be connected to a parameter in the delay template, so that it will control the value of the decibel parameter.

Thanks,

Jake

Mar 17, 2011 at 7:29 AM

Hi Jake,

The important thing is that the dependency is always from the UI to the plugin processing component(s).
So do not let your processing (DSP) components push data to the UI, but always let the UI pull data from the components (for displaying).
Value changes, of course are set from the UI onto the processing component parameters.

Assuming an architecture similar to the Delay sample, I think you could simple handle the SliderValueChanged event (too lazy to lookup the real name ;-) and pass the value to the correct parameter of the (correct) processing component. Note that when you use programs in combination with parameters, you have multiple instance of the same parameter (for each program one parameter instance of each parameter). So you have to manage the current/active parameter.

The obvious place to do that is the VstParameterManager. This class is meant to manage the active/current parameter for a processing component. It has an ActiveParameter property you can use to set the value property (dont use the ChangeValue method on the VstParameterManager).

Recap:

- Plugin contains (DSP) processing components
- Each processing component exposes (internal) a VstParameterManager for each parameter.
- The UI handles the 'changed' events.
- Changed event handlers call the correct VstParameterManager.ActiveParameter to set the new value.

There are no facilities for value smoothing (where you gradually change the parameter value over a short time). That is something you need to build yourself. A logical place for that would be the VstParameterManager. If you need an override on ChangeValue (its not virtual at the moment) let me know.

Hope it helps.
Marc Jacobi

Mar 29, 2011 at 3:09 PM

Hi Marc,

 

Have you had any luck using NAudio components in the VST plug-ins? I am getting FileNotFound Exceptions whenever I try to load my plugin into VSTHost, but the NAudio DLL is added to the references in the project and copied to output directory upon compilation.

 

Thanks,

 

Jake

Mar 29, 2011 at 7:43 PM

I haven't tried it myself, but I believe there are others that use NAudio in their plugins.

What is the filename that is reported back with the exception?
(its sometimes not the file you think it is ;-)

Otherwise you could try putting the assembly in the GAC (just to test it)...?

Mar 30, 2011 at 12:40 AM

The file is NAudio.dll. I'm not sure how to get the assembly into the GAC - I tried to drag and drop but it wont let me, and when I tried to use gacutil, it said a strongly typed key was not present. I'm having a lot of trouble getting that to work. 

I want to step back from that for a minute and ask you how I should get a control on the UI connected to a parameter, such as the Gain parameter in the VSTMidi example. I would like a control, such as a slider bar, to change the value of the Gain parameter. I know you did this in your Delay sample. Can you give me a rundown of how to do it?

Thanks in advance for all of your help!!!

 

Jake

Mar 30, 2011 at 2:00 AM

BTW, i got NAudio added to the GAC, finally!!! IT WORKED!

Thanks!

 

Jake

Mar 31, 2011 at 6:43 AM

Yeah, assemblies in the GAC has to be strong-named assemblies. This means you have to specify a key file in the project properties. The NAudio assemblies should work also if it is deployed in the same folder as you plugin assemblies. Do you also deploy the Core and Framework assemblies locally or are those in the GAC?

The Delay sample does not have any UI. Check the source code against for instance the MidiNoteMapper sample - that has a custom UI, you will not find a UI form in the Delay sample. The UI you see is generated by the host.

Connecting UI to parameters: I have a problem here. I've tried to explain it to you before but apparently I'm not using the right words. ;-) Lets see...
You have (say) a slider on the UI. You handle the ValueChanged event. In the ValueChanged event handler you access the VstParameterManager instance you have created (or going to) (refer to the Delay sample how to set that up) for this parameter. Now access the ActiveParameter Property and assign its new value.

Ok, this was the part from the UI 'down' onto the processing logic (layer). Now more info on how to setup the processing logic.

Suppose you have a DSP component that processes the Gain of the audio signal (a simple multiplication of the sample values). It is called from the AudioProcessor on a per-sample basis. The Gain component creates a VstParameterInfo instance in its constructor (or other init method) that contains the correct meta data for that paramater. Then it attaches a VstParameterManager instance and keeps a reference to the manager as a source for the parameter value. Look closely at the Delay sample code, it does exactly this (but with 4 parameters).

(The VstParameterManager manages multiple instances of the same (logical) parameter (info) -when using programs- and retains the previous parameter value when the parameter value has changed (VstParameter.Value). For more info see also http://obiwanjacobi.blogspot.com/2008/05/vstnet-programs-and-parameters.html

All you have to do now is to pass an array of VstParameterManager instances (one for each parameter you whish to control from the UI) to the UI when it starts/opens.

Hope it helps,
Marc

Apr 3, 2011 at 9:44 PM

Okay, I'm in progress with getting the parameters to work. I have another question for you. I am using the VSTHost and am unable to receive any midi input into my program. I copied the code from the MidiNoteMapper into my code and have it running there, and VSTHost seems to think that MIDI input is going into my plugin, but my plugin doesn't recognize that there is any midi input. Do you have any idea about this?

 

Thanks so much for all of your help,

Jake

Apr 4, 2011 at 6:24 AM

Yeah, I always have trouble getting that to work right. Just make sure the ProcessEvents method is called (by setting a breakpoint or enabling trace). If its not called and you can't figure out how to get VSTHost to supply you the midi, I would suggest you ask Hermann.

The VstHost forum:
http://forum.hermannseib.com/

 

Apr 5, 2011 at 11:27 PM
Edited Apr 5, 2011 at 11:28 PM

Marc,

 

I have been working on trying to understand how to get everything to work, and I am still struggling. To be honest with you, I am coming down to the line (my project is due in less than 2 weeks) and I think I need some more intensive guidance in the right direction. I was wondering if it would be possible for me to post/email my project to you and/or contact you via Skype or phone and see if you can help me get some basic things working, such as a parameter in the code connected to the UI, getting my AudioProcessor/MidiProcessor classes set up correctly, and, at the most basic level, helping me get my project set up so that only the classes I need are in the project? I think that one of my problems is that I have so many classes that I am confused as how they fit together. I finally was able to get the debugging to work, so I am able to see that VSTHost is sending in MIDI events, which is great news. I have no idea how to take those events and convert them to audio, though.

If necessary, I can compensate you for spending extended time with me. I don't want to take all of your time, as I realize you have a life, too :-) At this point, I'm honestly worried that without some external help I'm not going to be able to get this done in time to graduate.

I really, really appreciate any time you can give me.

I have uploaded the project to RapidShare so that it is easily accessible. And of course, if anyone else who happens to read this that could potentially provide help should feel welcome to download the project and do so. Believe me, it is very much appreciated. 

VSTiSimpleSynth Download

Thanks,

Jake

Apr 6, 2011 at 8:33 AM
Edited Apr 6, 2011 at 8:36 AM

Hi Jake,

I'm sorry, but I just dont have the time to help you with that. I have taken a look at your code however and I can give you the following pointers:

- PluginCommandStub: you dont need to override the parameter methods. The idea is that the framework handles that and calls your implementation of IVstPluginParameters. The way things were setup in the VS template (assuming you used that) is that all parameter changes would be routed to the correct VstParameter instance. The VstParameterManager instances that are created in the Gain and Transpose Dmp components will reflect these parameter values.

- Pass the VstParameterManager instances to your UI (via IVstPluginEditor). Once you do that you can call VstParameterManager.ActiveParameter.Value = newValue in for instance the attackPot_ValueChanged  event handler. It is really as simple as that.

- RefreshRoutine: You cannot call UI controls on a different thread (other than the thread they were created on). Make these calls indirectly using Invoke. You should not need a separate thread. Instead use the IVstPluginEditor.Idle method to call the refresh routine. Also you can use the PropertyChanged events that are generated by each VstParameterManager for each parameter. Make sure you check for re-entrance when changing the paramaeter yourself. 

Hope it helps,
Marc 

Apr 6, 2011 at 3:32 PM
Edited Apr 6, 2011 at 4:30 PM

VSTPlayback is not needed in this project. It is a class I wrote to pass audio to a waveout device. In a VstPlugin context, the host is responsible for audio playback.

VSTStream can also be ditched.

If I were you I would tackle synthesis in a straightforward way.

For example:

Have the 'amplitude' of the sinewave in Process set to 0 and change it to 1 when you receive a midi note start in processevent, then set it back to 0 when you receive a midi note stop.

Adding a delay/linear progression to this amplitude change with a counter of samples processed would provide a crude enveloppe.

Change the 'frequency' of the sinewave in Process according to the pitch of the midi note start in processevent.

Generate and mix multiple SineWave that have a harmonic relationship interval together and transpose the frequency of all sines linearly according to the pitch of midi note start in processevent.

Have the relationship interval configurable in the parameters and you get a basic additive synth.

The master volume control is the easiest part, just multiply amplitude by a value of [0, 1] linked to a parameter.

 

I'm also short on time to help you with specific implementation details but if you have clear goals, timeline and budget...

Apr 7, 2011 at 1:00 AM
Edited Apr 7, 2011 at 1:10 AM

> [...] I have so many classes that I am confused as how they fit together.

- Try right click -> find reference on class names in the IDE. If the class has no reference than it's probably useless/unfinished.  I've just counted the class in my VstHost solutions and discovered I have ~1000 class. Pretty easy to manage if you sort classes in solution folders.

Yury

Apr 7, 2011 at 2:51 PM
Edited Apr 7, 2011 at 5:01 PM

Wait, 1000 classes? That's crazy. Okay, I will look to see if I have extra classes I don't need. I am going to try to get my process method working in the way you described, Yury. If that would work in that manner, I would be very happy.

Marc, I am going to go back in and try to get my parameters working today. This explanation rocks - I definitely feel like I understand it better.

I will keep you guys updated, and I will also provide a link to updated code today.

Thank you both for all of your help!!

Jake

Apr 8, 2011 at 6:41 PM

Jake,

Drop me an email at obiwanjacobi at hotmail dot com.

I've got something for you ;-)

Apr 8, 2011 at 7:00 PM
Edited Apr 8, 2011 at 7:01 PM

I sent you an email!

Thanks,

Jake

Apr 9, 2011 at 9:24 AM

Check your mail ;-)

It is excatly what you asked for (I think ;-)

For other who like to see an example of how to implement parameter value manipulation thru a custom Editor UI: It will be in the next release of the VS Templates. If you can't wait: send me an email (see address above) ;-)

Hope it helps,
Marc

Apr 10, 2011 at 2:55 AM

Marc,

This is awesome - just what I was looking for!! Thank you so much. I will have an updated project available for examination soon.

I appreciate your help and your time very much.

Jake

Apr 10, 2011 at 3:13 PM

Marc,

I sent you an email last night looking for some additional help.

Thanks,

Jake

Apr 15, 2011 at 9:33 PM

Marc,

 

Thanks a lot for that example of hooking up parameters to the UI! I've got it working so that when you change a parameter in the host it moves a knob in my UI but I can't seem to get it working the other way around. When I move a knob on my UI it calls this function:

 

        private void lbKnob_KnobChangeValue(object sender, LBSoft.IndustrialCtrls.Knobs.LBKnobEventArgs e) {
            var knob = (LBKnob)sender;
            var paramMgr = (VstParameterManager)knob.Tag;

            paramMgr.ActiveParameter.Value = knob.Value;
        }

 

I can verify that the function is successfully setting the value of the parameter but that value in not reflected in the host. e.g. the parameters sliders in the host don't move. Do you have any idea what could be causing this?

 

Thanks

Rob

Apr 16, 2011 at 9:22 AM
Hi Rob,

Could you please post your question on the discussion list? http://vstnet.codeplex.com/discussions

I am going to answer your question, I just want every one to be able to read the answer. Saves me from having to answer each question more than once (at least, thats the theory ;-).

Thanx,
Marc

BTW:The sample you got from me is now available in source control (Support) and will (with the next release) be available as the Audio plugin VS project template.



From: [email removed]
To: [email removed]
Date: Fri, 15 Apr 2011 13:33:08 -0700
Subject: Re: Beginner to VST developing a Synth [vstnet:247943]

From: robcheese
Marc,

Thanks a lot for that example of hooking up parameters to the UI! I've got it working so that when you change a parameter in the host it moves a knob in my UI but I can't seem to get it working the other way around. When I move a knob on my UI it calls this function:

private void lbKnob_KnobChangeValue(object sender, LBSoft.IndustrialCtrls.Knobs.LBKnobEventArgs e) {
var knob = (LBKnob)sender;
var paramMgr = (VstParameterManager)knob.Tag;

paramMgr.ActiveParameter.Value = knob.Value;
}

I can verify that the function is successfully setting the value of the parameter but that value in not reflected in the host. e.g. the parameters sliders in the host don't move. Do you have any idea what could be causing this?

Thanks
Rob
Read the full discussion online.
To add a post to this discussion, reply to this email (vstnet@discussions.codeplex.com)
To start a new discussion for this project, email vstnet@discussions.codeplex.com
You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.
Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com