Let's Build a Synth with Juce Part 2 - ADSR and Playing Sound

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up everybody i'd like to welcome you to another juice tutorial and in this tutorial we're actually going to build our first synthesizer plug-in so it's going to be very simple uh and but you'll actually be able to get notes to play out of a synthesizer plug-in today so this is going to be very exciting before we get started let's remind you about your audio programmer community so you can join the audio programmer community on discord it's a great way to connect with other people who are into audio programming and audio software development we have audio developers of all different levels who are able to help each other out and talk about all things audio programming you can join us on theaudioprogrammer.com forward slash community and please join up and also the code from both of these projects is going to be on our github at github.com forward slash the audio programmer so you can grab the code if you're missing it and you can actually join and follow along so let's go ahead and get started so here we have two projects that are open at the moment we have our basic oscillator that we created in the first tutorial from the series and then we have this project called tap synth which is the uh kind of scaffolding the juice synthesizer classes that we set up in our last tutorial so what i'm going to do is i'm just going to open this up the this being the tap synth so we'll open this up in our ide uh actually before we do that i'm gonna just shut that back down again sorry about that uh we need to check a couple things so going to our settings in our producer what we want to do is we want to scroll down and one thing we want to do is make sure in plug-in characteristics we have checked in plug-in is a synth and also plug-in midi input okay so this is just letting the uh when they built when it builds the vst it lets it know that the plug-in is a synth and it's expecting midi inputs so it sets up the inputs correctly so uh it'll do that if you don't have both of these checked in it will not work correctly unfortunately another thing that we're going to do is we're going to make sure that our dsp module is added to to our juice modules so just go to add a module global juice modules path and juice dsp okay so now i'm just going to open that up in the ide and then here i'm going to open up the basic oscillator code up in the ide as well so we got two projects open at the same time and now first thing we're going to do is we're actually just going to take all this stuff and we're going to copy it from the oscillator code and paste it into our juice synth code so we'll take all of this stuff where we declare the oscillator and the gain we're going to put this in the synth voice class so we'll just take that put that there then we'll go to synth voice dot cpp and here we have a prepare to play method okay so we have this prepare to play method where we've got all of this stuff where we're doing our setup uh what we'll do is we'll copy this and what i'm going to do is i'm actually going to create a prepare to play method in synth voice okay so we don't have one at the moment i will put this before render next block so i'll just create a method i will call this prepare to play play and then let's see what arguments it takes double sample rate and int samples per block double sample rate it samples per block and since this is not a method that is coming from synthesizer voice we are not calling override okay very important and then in synth voice once again try to keep these methods in the same order it makes it easier to read so i can say void synth voice since this is from the synth voice class and then we've got repair to play and we have our sample rate and samples per block and then i'm just going to paste all of that stuff that we had in our oscillator class so we see that we're getting an error here because it doesn't have a identifier called get total num output channels okay so there's no way that i see that synthesizing the voice can pass that information in so i'm just going to add an additional argument here i will say int output channels and then i'm going to just call output channels here and then i'm going to go back into where i'm prototyping these methods and i'm going to call i'm going to add that argument as well okay so i'm just going to build this make sure this actually works very quickly and in the meantime i can actually close out the basic oscillator stuff and so that that built successfully so that's fine that's good to go so so far so good so now what we need to do is one thing that i like to do when whenever you have any of these prepare to play methods where you need to pass some information before uh before we actually call it in our audio callback i actually like to have a boolean in here to make sure that i've actually uh declared this method that i've actually used this method uh so one thing that i'll do is i will create a boolean here i'll just call bull is prepared i'll set it to false this is just a check to make sure that we aren't trying to use anything in our in our audio uh in in our audio callback that before we've actually instantiated it so is prepared we will set to true once this prepare to play method is actually called and then in here what we could do is we have this method called jsert so this is a way that we can actually say if is prepared hasn't been called then we want to stop execution of our project and uh we want to say hey you forgot to call prepare to play okay so i will i'll show you a demonstration of what that looks like a little bit later in the tutorial so now we've pasted all of our oh nearly all of our uh oscillator code sorry i need to go back into the oscillator code again because we've forgotten one thing which is very important which is actually putting the oscillator audio information into our output buffer so now we have all of this stuff that's in our process block in our basic uh process in our basic oscillator that we created i'm just going to copy that and now i can actually close this out and we're just going to put this in render next block where our actual audio code is uh being called now it's going to give us a complaint that this it doesn't know what buffer is that's just output buffer so i could actually just copy that i can paste it here and now we should be good to go remember render next block is actually just being called in our plugin processor method so if we go down to the plugin processor we have synth dot render next block okay so that is what is actually uh calling that on all of our voices okay so now what we need to do if you recall just a really quick review we have this class that we've created so i'll try to explain this as plainly as possible so we have our class that we've created called synth voice so this is our own class this is inheriting from synthesizer voice which is a juice class okay so in our plug-in processor what we've what we've done is we're adding this class that we've created synth voice to our synthesizer okay and then what we need to do remember we need to call that prepare to play method right where we have this prepare to play method and we need to call that before we actually call render next block so what we're doing is we will say we will say 4 and i equals 0 and then we have this method where we can get our voices so we have i is less than synth get num voices i plus plus and then what we will see here is we would we would think at first that we could just call synth uh get voice i which gets each one of our voices and we let's have a look at our juice documentation here so i can show you what i'm talking about so in our synthesizer reference we have this method called get voice okay which returns a synthesizer voice now this is where it may get tricky for you if you're just starting out so remember it returns synthesizer voice which is a juice class okay now our class is called synth voice it's not called synthesizer voice so we actually need to get our class because we have this class call we have this method called prepare to play so we've created that and that we we won't have access to that method because this is returning a synthesizer voice okay so if i if i try to call prepare to play we see that there's no method called prepare to play it says don't know when i'm talk don't know what you're talking about okay let me turn off my phone sorry about this uh so so what we will uh so what we need to do is we actually need to make sure we we need to do a cast on the the synthesizer voices and cast them as synth voices and if it's and if it's successfully cast as a synth voice then we can call the prepare to play method so we can say if uh and then we will do auto voice equals dynamic cast and remember we want to try to turn our synthesizer voice into a synth voice and remember this is returning a synthesizer voice pointer and so we need to return a synth voice pointer okay and in here what are we trying to turn into a synth voice pointer each one of our synth voices right so we go synth get voice i and now we can say if we've successfully dynamic if we've successfully casted our synthesizer voice pointer as a synth voice pointer then we can call then we know it's a synth voice pointer and we can call this prepare to play method so i could say voice remember this is a pointer so we need the arrow operator prepare to play and now we see that prepare to play pops up and then here we can just call our methods so we've got sample rate samples per block and remember we have that method that processor method called get total num output channels so that is fine now okay so now we are good to go so i think so i think that's fine for now and now what we want to do is we want to have a way that we can actually control the uh when we actually turn the sound on and off right so normally in a synthesizer that would be an adsr attack decay sustain and release and that would control when we're actually it would know when we're actually pressing the key to actually turn the sound on and when we're releasing the key to turn the sound off so juice has a handy adsr class here we are so we have this adsr class and we have kind of it's uh it's child class called parameters adsr parameters where we can actually declare an attack decay sustain and release that we can actually use to control when the sound actually turns on and off so so here we have note on and note off methods we have a reset method as well so let's go ahead and start using some of this stuff so first thing that we'll do is we will create an adsr object so i will just put this above our oscillator doesn't really matter so we've got juice adsr and i'll just call this adsr and then we have to create some adsr params adsr parameters i'll call this adsr params i'll just build this while i'm going to the synthvoice.cpp just make sure that we're actually building okay yep so we're fine so in here now we can call so let's see here so once again whenever you're using these things it's good to make sure that they're uh if there is a some sort of method that you need to call to set the sample rate so we see that there's a method here called set sample rate and we will need to use that so we could say adsr so i'm going to just put this above this so adsr set sample rate and then here we pass the sample rate okay and then in and then that's it for that and then going back to our documentation we have two ways that we can actually call this method we can use this git next sample which does sample by sample processing i'm going to use this one called apply envelope to buffer where i can actually pass in the audio buffer the start sample and number of samples that i want this to apply to and we can do this conveniently like this so so in here in render next block uh one thing one thing that i'm going to do actually is i'm going to make sure i want to make sure that prepare to play is actually called and that all the sample rates are set before i actually call before i actually try to do any audio processing so one way i could do this is i could do a boolean a lot of times juice actually has their own checks here but i like to just do a double check so i'm going to call a boolean is prepared i'll set this to false and then in the prepare to play method once all of this is called i could call is prepared equals to true and then in render next block what i want to do is i want to make sure that all of this uh that all of our objects have their sample rate information before i try to do anything so what i could do is i could do what's called a assert and then i can say is prepared uh to make sure that that's true so if i just say is prepared then that that will be fine you could also do is prepared is equal to true that's saying the same thing so both of those things are the same i just like to say is prepared so that's uh so that's fine and now we have all of this stuff and now we have our oscillator and our gain and all we need to do is we just need to apply our adsr to it so i can actually just say adsr after all of this after the oscillator has done its thing in the audio block and i can say adsr apply envelope to buffer and in here i just put my audio buffer so we got output buffer start sample and num samples okay now if you're looking at this carefully you may say why how can you do that because the adsr is you may say the adsr isn't going to apply to the audio block because aren't you putting the aren't you putting the oscillator data into this audio block okay so what so when you're trying to apply the adsr to the buffer that's not going to actually apply to the code that you put in the audio block well if you recall going back to our first tutorial in this series i was telling you that the audio block an audio block is actually just an alias it's actually talking about the same thing as the output buffer okay so if i'm putting if i'm putting audio data into the audio block i'm actually putting it into the output buffer okay so what that means is that when we get to this line of code 65 output buffer will contain all of the audio data that we've put in it through osc.process okay so i hope that that makes sense okay so audio block audio block is the output buffer basically is what i'm saying okay so it's just another handy name for it so i hope that doesn't confuse you and once again going back to plug-in processor.cpp then we have our process block where in here later we will do our audio processor value tree state and put our attack decay sustain and release and then we call this synth dot render next block which calls synth voice render next block on each one of the voices so now we should be able to go ahead and uh actually test this out and we should have a synthesizer that we can actually play uh oh actually i forgot something else we need to actually apply our envelope to when we're actually playing notes so going back to our adsr we have these methods called note on and note off okay so what we will do is we will uh we will actually look at where we could put those okay so a natural place for note on to me would be where we have adsr start node okay so i can just say adsr note on and then in stop note we can just say adsr note off okay another thing if you're watching carefully is you might say oh but our oscillator is always going to play at 220 hertz okay so that's always going to play at the same frequency same note so that's not very handy is it so we could actually just take this we're going to cut this out of our prepare to play method and we can actually use our midi note number so we can actually take in the midi note number that the user is playing and we can actually use that to change the frequency of our note so what we will do is i will paste set frequency in here and we actually have this handy juice method from the juice midi message class and i think it's called get midi note in hertz here we go and in here i can just pass the midi note number and it will change it to the corresponding frequency in hertz so that's how we're going to set our frequency for our oscillator so now i think we're ready uh if you're an x code so what i'm going to do is i'm going to open this up in our daw so i use ableton so to do this in xcode as i always say you can go so i'm building for vst3 you can go down to edit scheme then in executable you would choose other and then you would go to your applications folder and choose the application you want to open this up in and i choose ableton okay so that's how you would do that there visual studio is a little bit more complicated i should one of these days i should do a tutorial on how to actually do that in visual studio so i will do one of those at some point so now we're opening up ableton and i hope all of this works the first time around so in here i built for vst3 so it'll be my vst3 folder just go down to your company and we will just put this on a midi channel and we see that we have this synth and it actually doesn't have any ui or anything but if i press a key oh it's very soft uh i'm not sure if you can actually hear that but it uh but it's actually playing you can see in the vol using the volume meter there okay so so yeah you can see that it's actually playing one second i'll actually just turn it up just a little bit just for just in case there's this utility just turn output game okay so i hope you can hear that but yes the sound wave is actually playing and that is uh that's it so you built your first synthesizer congratulations okay so we don't have a ui yet we can set up the ui very soon and uh that will be the subject of our next tutorial so we also haven't actually giving given the adsr uh as parameters attack the case sustain and release so we can't actually modify the sound just yet so this is just a basic synthesizer like the hello world of synthesizers in uh juice so that is where we're going to end the tutorial for now the next tutorial what we'll do is we will actually start setting up our audio processor value tree state and with the attack decay sustain and release uh parameters and actually be able to control our sound a little bit and change oscillators so uh so i hope you enjoyed this tutorial please give it a like and subscribe if you haven't subscribed and i will see you next time
Info
Channel: The Audio Programmer
Views: 3,755
Rating: undefined out of 5
Keywords: synth, juce synth, synthesiser, synthesizer, synth vst, synthesizer vst, juce, juce framework, adsr, envelope
Id: AfrAWH5i-pQ
Channel Id: undefined
Length: 23min 49sec (1429 seconds)
Published: Fri Dec 18 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.