Juce Tutorial 62 - The Audio Process Block

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 going to talk about the process block or what some people call the audio loop or the audio callback and this is the main guts of any sort of audio app or plugin where you have audio information coming into and going out of your plugin if you're doing any sort of signal processing or digital signal processing this would be happening here in the process block where you'd be making some sort of calculations in real time on your incoming audio make some sort of change and then you would have resulting audio that would be going out of your plugin so I'm going to do this tutorial to try to clear up any sort of misconceptions that people have about the process block so I know that through my time and my journey in audio development I've had many misconceptions about the process block myself and I see this as a common question that people ask in the development community and I hope that I could clear up some of these misconceptions and if you have any sort of information that you'd like to add about the process block or any sort of Corrections that you'd like to make I invite you to do so in the comments below so without further delay let's go ahead and get started so we see that we have two arguments for our process block we have references to our audio buffer and our audio buffer is what actually contains our audio information as a set or a vector of floats then we have this MIDI buffer which is the same thing but it contains many messages if we had some sort of MIDI controller connected it would contain the many messages of when we're pressing a pad when we're moving a slider on a mini controller and so on we're not really going to talk too much about the MIDI buffer itself we're going to concern ourselves mainly with the audio buffer so going to mime 137 we have this line that says scope node to normals I'm going to give you my best general explanation of what this is as I understand it so my understanding is that when your CPU tries to do calculations on very very small numbers and I say very very small in terms of if you had let's say a decimal and 15 zeros and then some numbers and it was trying to do calculations on this my understanding is that your CPU load actually spikes when it's trying to do calculations on those very very small numbers and this note to normals is to prevent that from happening and that it zeros out or rounds those digits I'm not sure exactly how it happens I've looked a little bit into this and it got very deep very quickly and I just said okay well I have a general understanding of that okay so so the note to normals object is there to prevent your CPU load from spiking when it's trying to do calculations on very very small numbers then in lines 138 139 we just have these local variables that are being created that give us a total number of input and output channels for our sound card and then a common misconception that I see from people is why I'm 142 where it says buffer not clear and it goes from zero to buffer get number samples now a lot of people say how is audio information actually happening in this process block if we're actually clearing it out before anything is happening well if we take a closer look at line 141 what we can see is that I is total number of input channels so I'm operating in a stereo scenario here so let's say that my total number of input channels is 2 and let's say that my total number of output channels is 2 as well and if we take a closer look here we could say okay is 2 2 is not less than 2 so this line of code would never actually run in my scenario and in most scenarios that would be the case okay so the buffer dot clear is only happening in scenarios where you'd have more output channels than input channels and it would clear the other output channels out because we wouldn't be using this and so it's just clearing those extra channels out if we have more output channels than input channels going down further to 144 through 147 we see that we're iterating through channels that once again our total number of input channels in this scenario is 2 so we have channel so this would be iterating through channel 0 and then channel 1 and then another object of confusion or another subject of confusion is lime 146 we have this audio pointer channel data equals buffer get right pointer or the channel so what is the right pointer a right pointer is a pointer that actually lets us modify our audio information so if we were doing some sort of DSP algorithm list they were doing filtering or we were doing some sort of gain plug-in or something like that what would happen is that we're actually getting access to that audio value that's in our vector in our buffer and we're actually able to change that somehow okay so that's what that channel data is so we also have available to us what's called a reed pointer and we see this as well commonly in the process block so let's just say Reed let's let's say Ari pointer equals buffer get read pointer and we have channel okay we see that this is cost right cost means we can't change it and of course it's a repoint err which means that we're just reading it so why would we want to know the information about our audio buffer if we weren't trying to change it okay so one scenario where we might use a reed pointer might be if we were outputting the level meters out to our UI right we would want to know we we would want to be able to read our audio information so we would want to put that out to our UI right but don't actually need to make any sort of changes in the audio information itself in that scenario so that's why you have a repoint er and that prevents the changes from actually happening to your buffer as you're trying to just get a reading on that and put it out to your to your UI side to repaint your meters but then we have this right pointer channel data right pointer and let's say that we're trying to do some sort of audio processing right so there are two kind of scenarios that I see there that I've seen in my experience when it comes to audio processing one scenario is where it's trying to do processing on a buffer load of information at once right so one way that we could depict this is let's say we had a filter and we were trying to do processing on the audio information and what we could do is we could do a we could do it on a whole buffer at once by doing channel data and then normally it would say buffer get numb samples okay so if we had if we had something like this right where we're trying to process and what this is doing is that it's getting a buffer load let's say that our buffer size is 512 let's say it would be getting 512 samples at a time and then perform this filtering process on the on the audio buffer itself okay they'll be doing that all at once okay and normally if you click into the process if you have like some sort of process method that was happening here normally tried to click into that you would see that there is actually a for loop that goes from 0 to buffer get numb samples that and then it says you know filtered up process on on those on those samples so the other option is if you have if you're doing this on the sample by sample basis right so in that case you would say for auto sample equals zero sample is less than buffer get numb samples plus plus sample right now you have a scenario where you're able to do some sort of processing here so typically this type of process would look something like this channel data a sample position equals and then you would have I don't know let's say channel data then let's say you were you were doing a gain times the gain factor so here we see that we're doing this now on the sample by sample basis where you're taking one sample and then you're multiplying it by a gain factor let's just say it's 0.5 right so let's say this game factor is 0.5 then any sample that you have in this buffer would be cut by half right so be half half the amplitude of what it was before so this is so these are the two ways that this processing happens right so this filter this filter dot process would normally have a loop like this that's in this that's baked into this process method right or sometimes you have to do it sample by sample like that okay so those are the two types of processing that I've seen so going back to the process block one misconception that I know that I've had in the past is I've always thought to myself well I've heard that the process block is a high priority thread so it's getting called very very quickly and the question that I've had in my well how quickly does that process block get called how often does it get called and I used to think in my mind for some reason well the process block must get called at sample rate sample rate times per second right so here I have a text editor and it says how many times a second does the process plot call so if we look at our buffer let's let's say that we have a sample rate let's let's picture a scenario here where we have a sample rate of let's just say 44100 so the app has to process 44100 values or samples a second right then we have of this this variable that we call buffer size right let's just say it's 512 okay so normally it's a power of two 128 256 512 sometimes it's not though okay but most of the times it is so that's referring to this buffer get number of samples how many samples we have in our vector that we can process at one time so then the question is how many times a second does this process block call so we see just by some simple math here we have to calculate 44100 values a second which is our sample rate and that each time that we call through this block we're processing buffer size samples which in this scenario is 512 right so we see that the audio callback actually happens sample rate divided by buffer size times a second okay so that's so there are actually exceptions to how this happens so we're assuming in this in this scenario that this 512 is stays constant and then this is just what happens every callback but da Wu's actually handle this differently depending on the da W okay so there are some that will just change the rate on you right so maybe your buffer size might be 512 for a bit but then it might be 128 and then sometimes it's not even actually powers of 2 is something like 46 or something like that okay so but you don't really have to worry about that as long as you just have this processing right and that you're just doing the processing on whatever is coming into your process block you'll be fine okay but that is that is just kind of a very generalized answer for you of when when you're thinking about how many times does this process block actually call so now I'm going to talk a little bit about some things that you do not want to do in the process block so the process block runs on a thread called the audio thread and the thread is a high priority thread and the reason that this high priority is because we want to make sure that that audio information is always coming through and here are just a few basic things that you don't want to do in your audio thread there are there are loads of discussions that you see about this in the juice forum and also on the other programmer discord about things that are blocking or things that you don't want to do in the audio thread so there are whole dreams of discussions about this I'm just gonna give you kind of two things that you don't want to do in your audio thread so the first one would be something like this you don't want to console out so like let's say that we were innocently trying to find out what the values of our actual audio were in in our process block all right that's something that we don't want to do okay and what you'll find is that if you run this that if you had incoming audio you'll get some sort of stuttering or buffer underruns basically the audio wouldn't sound right because you're trying to console out and this console this consoling out actually blocks on your audio thread okay that's what they call it they call it blocking okay and that you don't want to block on your audio threads at that that's cool if you just want to kind of experiment and just see like hey are those are those samples looking like they might be right then that's cool to do but as soon as you do it you just want to actually get rid of that method okay make sure that you don't have that in your process block so no constantly now on the process block the other thing is you don't want to allocate memory on the audio thread okay so let's say we had a vector and that we were doing some sort of vector resize method okay and you know we wanted to do we wanted to make it 512 values or something like that okay once again this method call or any sort of memory allocation we don't know how long that's going to take okay so we do not want to call anything like vector resizing on the audio thread no memory allocation no vector resizing on the audio thread and no consoling out on the audio thread okay so that is a very generalized overview of the process block so so yeah so here's some those are some basics of the audio callback and I hope you enjoyed this I hope you got some knowledge out of it and as I said as always feel free to add comments below if you have things that you want to add and I will see you next time
Info
Channel: The Audio Programmer
Views: 2,818
Rating: undefined out of 5
Keywords: juce, juce framework, c++, digital signal processing, creative programming, dsp, audio callback, audio processing, vst design, create vst, audio developer, audio development, audio programmer
Id: Y5MhjRxfNvA
Channel Id: undefined
Length: 17min 16sec (1036 seconds)
Published: Thu Dec 19 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.