Juce Tutorial 40- Building a Delay Plugin Pt 1 (Creating a Circular Buffer)

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 for this tutorial what we're going to do is we're gonna start going into this process of building a simple delay and the first part in this process is going to bill be building a circularbuffer now building a circularbuffer in this tutorial we're actually we're not actually going to be producing any sound we're actually just going to build the circular buffer itself because it starts getting a little bit fiddly just trying to explain the ins and outs of copying from one buffer to another and what happens when you get to the end of one buffer okay so it gets a little bit fiddly so I'm going to break this down into a couple parts so this particular method isn't something that I came up with and if you if you look online there are actually quite a few resources to actually look at how to build a circular buffer this particular method is one that I've picked up from Daniel Wallace who's a senior software engineer at Rowley and he doesn't know that I've actually done this but I've actually just looked at his delay plug-in and I've pulled this out so I hope he doesn't mind I'm sure he's not going to mind and Daniel Wallace is an amazing software engineer it needs taught me so much and and so I'm gonna share this with you and it's just one part it's just one little part of his plugin so yeah it'll be all good and so building a circular buffer is something that you need to know how to do if you're going to make just about any effects plug-in really and this is a process where you're taking the data that's coming in so you have this audio that's coming in that's being represented by values that are in your buffer right there floating point values they're in your in your buffer and then this is a process where we're taking chunks of data and what we're doing is we're copying it from one buffer to another buffer now in this buffer we might do something that some some sort of processing where we might want to look to values in the past take that chunk of data and then put it out like in a delay or we might want to run it through a distortion algorithm and then build like a distortion unit so this is a process that you need to know how to do if you're gonna build just about any sort of effect plug-in and I'm gonna show you the first part of this process like I said we're not putting we're not doing actually any sort of audio output today I'm just teaching you how to build the buffer itself so the first thing that we need to do is so as I showed you we have this buffer is of an audio buffer float type okay you can think of it kind of as a vector sort of and so what we need to do is we need to create another audio buffer so I'm going to do that now so we're gonna call this audio buffer this is gonna be a type float I'm gonna call this M delay buffer so I put an M here this is actually a little thing that I picked up from Daniel and also from another guy that I've been working on a project with named Matthew Garcia fantastic engineer you should follow him on Twitter he's just the man he's taught me so much and this M just means member variable okay this is just something that we can put in front of our global member variables just to say just to say so when we're looking in the code it says hey this is a global member variable okay as opposed to maybe P or an MP in front of it which would be member pointer or pointer okay so so now I've got this delay buffer and what I'm gonna do is I'm going to give it a size because it doesn't have this it doesn't have a size yet and I can use this method called set size right so I'm just going to go in to prepare to play I'm assuming by this point you know what prepare to play is so gonna go through that with you again so we're just gonna go em delay buffer set size and here I'm just going to before I put these two variables I'm just going to actually just set a couple variables here so I'm going to do constant so you know that Const I hope you know that cost means that it's a value that you can read from but you can't actually change the value okay so something like the sample rate or how many samples per block or how many input channels we have once we start once we start actually playing audio those are really values that we want to change so what I'm going to do is I'm going to set the number of input channels to this to this variable so I'm going to just call this number input channels equals get num input channels why is that why was that crossed out interesting okay so hmm what happened there hmm I think it's good I think it's now get total number of input get turtle yeah they're just get total number and put channels that's it so sorry about that hitch there and so now I can just put num input channels here now the number of samples that we want to make it so here's a situation where we have a buffer and we have audios coming into this buffer we want to take that data we want to copy it to another buffer right now we run into a situation where we might want to access data that's in the past okay so if we wanted to make a delay and we wanted to take that chunk of data and we wanted to keep delaying it then we need to be able to access that data right so if it's data from one second in the past then we want to be able to access that data and we still need to be able to grab it to keep delaying it so so what we want here is I'm going to do another constant and I'm gonna go delay buffer size equals so now if we think about this right if we have a sample rate of forty four thousand one hundred values a second and then we have our sample tour block which is going to be probably 512 if I want to access two seconds of that that would be that would be 88 thousand so that would be 88 thousand two hundred values times samples per the times samples per block squared right so so if I wanted to access one second we would have sorry sample rate times samples per block all right so that's that's how much audio is gonna play in one second okay now let's say I want two seconds of that okay so I'm just going to do two seconds of that just like that okay and that gives me two seconds of breathing room in my delay sample buffer so here I can just set this to delay buffer size and that's going to give me two seconds of audio that I can access in the past that's going to that I'm going to be able to do whatever I need to do okay so that's the reason why this delay buffer is not the same size as our main buffer and as you can see that's going to cause us to need to do some a little bit of math modulo a trickery in order to be able to wrap these values around okay and you'll see what I mean in a second so now we're gonna get down here to the process block I'm just gonna erase this but keep this for loop so we're gonna have this for loop we're iterating through the channels right so we're gonna have channel 0 it's gonna do some processing then this is gonna go to channel 1 then we're gonna do the we're going to do the same processing right so that's for our left and right channels so first thing I'm going to do is I'm just going to create some very variable x' to make this a little bit quicker for us to write so so if we can do constant buffer length equals buffer get num samples okay so this is just so I can just have a little so I can just write buffer length rather than buffer getting them samples every time because it looks a little bit Messier every time you write buffer dot getting them samples so I'm gonna do the same thing for my delay buffer equals and delay buffer getting samples okay so you can think of these as like kind of like vectors I guess just how many values we have in a sample block right in a in a block of audio code right and those are going to be a collection of floating-point numbers now we're going to and what we need to do is we need to be able to read from our main buffer and read that block of data and then take that block of data and place it into the delay buffer so the delay buffer is just the same thing as our main buffer but we're just taking values we're just copying it from our main buffer to the delay buffer okay but because these are two different lengths then we need to do a couple different things just to make sure that everything kind of plays nice with each other and we're not running out of bounds on our buffer okay now what we're going to do is we're going to create right read pointers for our for our buffer and our delay buffer so what this means is that we're going to so we're not actually writing to them okay we're not actually changing or placing anything into the buffer we're just reading from one buffer and we're just gonna place it into another buffer okay and we're just gonna actually copy it to another buffer and the way we're gonna do this is we need to create read pointers so we got Const once again these are things that we're just reading from we're not actually trying to change them that's why I'm putting them as Const okay so we got Const float let's just say buffer data those buffer get read pointer and here I could put the channel number and where remember we're in this for loop here so I could just put channel here and then I can do the same thing for the delay buffer equals delay buffer get read pointer once again this is stuff this this particular implementation is not something I made up it's actually coming from my good buddy Daniel Wallace and it's coming from a delay that he's actually created I'll go ahead and link you to to it below in the description and if you don't know Dan dan is the absolute man and he's one of my favorite software developers so big up to you Dan so now what we're gonna do is we need to come up with a little bit of math that's going to help describe what we're going to how we're going to work with these buffers when they come to the end of their length right because there's going to be a point where we get to the end of our delay buffer and we want that to wrap around right so so the first thing that we're going to do is we're going to be able so so the first thing that we're going to do is we want to be able to wrap this delay buffer around so that when we get like let's say we have our delay buffer is like ten values and we get to nine and ten and we need to write we need to copy the next value from our main buffer into our delay buffer then we need to go back to two index zero and copy that next that next value in index zero okay and this is how we're going to do that so we're going to create a another variable we're going to call this right position and this is something that I've learned from Matthew Garcia where I can just initialize that right here using these curly brackets right so you can use a member initialization list as well in your constructor if you want to but but this is something I quite like doing this right here because this this actually just lets me know I can just look at my global variable and I could say that's the initial that's the initialization right there and I can just see that right then and there okay so so what we're going to do is when we first thing we're going to do is we're going to copy the data right from main buffer to the lay buffer and I'm going to show you how to do that and then once we've copied those values let's just say it's 512 values because that's common that's common buffer length right then we're going to say m right position which was initialized as 0 I'm going to so if we've copied 512 values from the main buffer into our delay buffer then we want to move the right position because we want to make sure that the next value that we actually get ready to copy into the delay buffer is value 513 and not value zero right so this is why I'm doing this M right position plus equals buffer length okay so this is this would be saying the first time that I've the first time that I've copied this data 512 values now I'm gonna move this 512 that I'm gonna move the right position 500 2012 values over on the delay on the delay buffer so that the next so that the next value that I write is value 513 all right and then I'm gonna say now this is going to be modulo okay delay buffer length okay now the reason that I'm doing this is to make sure that I wrap around when I when I actually get to the very end of my delay buffer delay buffer right so let's say that my delay buffer is of length 10 right and that my right position is at 11 okay then what's going to happen is that you're gonna do 11 modulo 10 right which means 11 divided by 10 and now we're just looking for the remainder is going to be 1 right so because 11/10 equals one time and it gives you one remainder okay don't know what modulo is I would HIGHLY highly advise that you check it out because you're gonna need it all the time in DSP okay just means that when we get to the end we rap we're just wrapping it around okay we're just wrapping it around to zero so when we get to ten values if delay buffer length was ten values once we get to ten the next one would be ten so so so when we get to index ten then when we get to this point to this line of code it would say ten divided by 10 equals one so because 10 goes into ten one time but the remainder is zero so the next place that would write would be into index to zero okay I hope I hope I had I made that clear to you okay so modulo very important okay so now we need to go through this business of actually writing from the main buffer to the label to the delay buffer so we need to do a couple checks here okay so first one is if the we need to check that the delay buffer length is greater than the buffer length plus the right position okay then I'm gonna show you this now okay I'm just gonna bring up my TextEdit here and just give you a really quick example okay so let's say that we have a buffer that has ten values and that we've created a delay buffer that has 20 values all right and then our right position is zero okay so now we're saying okay so we have delay buffer which is 20 Plus so so we need to check that that is greater than our buffer which is ten plus our right position which is zero right but let's say we get to a point where we say okay now we're at a point where we're at buffer equal the buffer is 10 right that stays the same that doesn't change plus the right position is now 11 right so we've copied 10 values in and now we want to copy the next we want to copy the next value so 10 plus 11 is 21 right and we can see that 21 is greater than 20 so what are we going to do so we need to make sure that so so so now we're in a position where we have a right position is at 1111 values have been written into the delay buffer so far which means we have nine values left right so we got nine values left right now how are we gonna get these remaining nine values into this delay buffer so what we need to do is we need to go delay buffer which is 20 right that's length of 20 minus the right position right and for our next iteration we're going to be able to copy nine values okay and that then that gives you so we have the right position is 11 values right the next iteration we've copied nine values that gives us 20 right so now we've filled our delay buffer and then for the next one we need to go back to zero okay so that's that's why that's why we're doing this here to make sure that this that this wraps around and that we're able to right all of our buffer or main buffer values into our delay buffer and account for those different lengths so the way that we do that is we're going to say let me think here is we're going to say so we're gonna say m delay buffer so we got our delay buffer we're gonna copy this from our main buffer so we're gonna take what's in our main buffer and we're just gonna copy it to our don't delay buffer okay for for this first situation it's fine because our because our delay buffer length is greater than our buffer length plus a right upper plus our right position so we're fine in terms of length here okay so to fill in these arguments so copy from with ramp means that I'm copying from this from my main buffer to my delay buffer and this lets me put what channel I want a copy from what sample that I want to start with and also lets me do a gain if I want to change the volume of those okay we're not going to worry about that for now the the gain part but channel we can just since we're in this for loop here I can just put channel right just like that and that's going to automatically iterate through our channels so our sample is going to be the right position okay so we want to go so if we started and we went 512 samples in then that's going to move our right position there so that so that we're going to be able to copy the next chunk of data and not go back to the very beginning again okay our source that we're copying from is going to be our buffer data okay so we're just getting our our data we're just reading the data that's in our main buffer okay the number of samples that we're going to do is buffer length okay that's just how many samples that we have in our buffer and here I'm just going to put 0.8 0.8 don't worry about that for now that's just the gain right so now what we need to do is we need to we need to account for when this when the buffer length and the plus the right position is greater than the buffer length okay so as I said before all right we need to do we need to create this equation here delay buffer - right position okay so we need to do else and I can do Const int I'm doing an int here because we're accessing index values right so so index values as in the value of index 5 index 7 you know a vector is not going to have an index of 7.5 right so that's the reason I'm doing that so I'm gonna say I'm gonna call this buffer remaining and we're going to do the delay buffer length - the right position okay so just like I did here so we have the length of the delay buffer - the right position again that tells that'll tell us how many values that we need to copy in that next iteration so like I said before you know our right position is at 11 and then we have nine values left in our in our delay buffer that we need to that we need to copy okay so that's how we're doing that we're saying delay buffer - the right position gives us shows us that we have nine values that we can that we can still copy to the delay buffer and that's how we're doing that okay so we've got M delay buffer copy from with ramp you got channel and we got once again we're doing we're going from the right position and then once again we're going from buffer data or copy that we're copying from our main buffer and then our number of samples is the buffer remaining okay that's the the number of values left that we then we need to valid that we need to take and copy back into our delay buffer then once again I could do this zero point eight and zero point eight because we're not going to worry about that from now and then what we do what we do so now we've come to the now we've come to the end right we've come to the end and now what we need to do is we need to set or we need to set our delay buffer back to to the to the beginning to copy from the beginning of the next chunk of data and the next chunk of buffer data right so which means that we go M delay buffer copy from with ramp channel and this is gonna start with zero right so so so what we've done here going back to our example is we have nine values left right so I had I had eleven values that I'd have filled up and now the next so so then I've filled it up with nine so now I've filled it up I've filled my delay buffer up with twenty values right so my delay buffer is filled so now I need to go back I need to go back to the beginning of the delay buffer I need to go back to zero again right and I need to start overwriting what values were in my or in my delay buffer okay so once again we're doing buffer data then we're doing the buffer data let me think about this buffer length minus buffer remaining okay that's 0.8 0.8 okay so we got buffer length so so what we've done is okay so we've said so we said okay so we have each each time we've copied each time in this example we've copied ten values right so we're going through ten we're going through ten values right each time that we're going each time that were going through this iteration so what I did was I copied so then I copied nine values right and now I still have one value remaining in my in my iteration that I still need that I still need to copy to the delay buffer from my main buffer and that's what this little line of code is about is saying okay so now I'm wrapping around I'm going to I'm going to the beginning of my delay buffer again but now I have to take the rest of the the data that's that's remaining still so in this short little example I have one value that's still remaining and I have to copy it to the zero index of the delay buffer ok so that's all I'm gonna do for this for this time around okay because I think that's quite a bit of information to digest and this is something that we can later probably put in a function a whole separate function but I'm just gonna leave it here for now because I feel like if I do any more I'm gonna mess up okay so this we're gonna end things and I hope you enjoyed this tutorial and be sure to join our patreon the patreon support group if you want to donate to the channel if you don't it's cool you can just still do this for free and also be sure to check us out on discord we have a lot of great talented developers from all over the world some people from Rowley and some people from some other really great companies around the world that are in the group and contributing and having fantastic discussions on different things so I hope you can join and I hope you enjoy this tutorial and I will see you next time
Info
Channel: The Audio Programmer
Views: 10,597
Rating: undefined out of 5
Keywords: audio effect, vst, audio programming, audio development, juce framework, delay, circular buffer, digital signal processing, dsp, tape delay, audio dev, creative programming, c++, cpp, cplusplus
Id: IRFUYGkMV8w
Channel Id: undefined
Length: 31min 42sec (1902 seconds)
Published: Sun Aug 19 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.