Juce Tutorial 24- Building a Synthesizer Part 4 (Controlling Parameters & UI)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up everybody I'd like to welcome you into another juice tutorial and today what we're going to do is we're going to build upon the synth tutorial series that I've been doing the past couple tutorials so what we're going to do briefly is we're just going to review what we did last time and we're gonna build upon that a little bit for this tutorial so what we did last time is we use the maximilian sound library to build a couple synth components so we have a envelope that we built here in adsr then we have an oscillator that we've called the wave and that's operating at a frequency we've also added the Benny functionality so that when so that when we press keys on our MIDI keyboard that we're actually getting sound out and that that's being controlled by the adsr so just to go through the routing that we did so we have a sine wave oscillator and that's going into this adsr that we're calling the sound pardon me and then we have the sound outputting through our speakers so now what we're going to do is we're going to get a little bit more involved in that we're going to actually start developing some UI elements so we're going to start with the adsr first probably just the attack and release today just for times sake and what we're going to do is we're going to set up UI elements so we're going to set up some sliders that where we're going to be able to control the parameters of our attack and release and we have a couple different things that we need to assure when we're actually setting this up so first of all in if you if you have followed along with our tutorials before you recall in the game tutorial that basically we had two sides of the plugins so we had the plug-in processor where we had our kind of back-end DSP functionality and the process block where everything is actually going out through the speakers I'm looking for my process block at the moment where is it yeah oh sorry about this so here's our process block so this is where everything is actually going out through the speakers you can see that I'm calling from the synth voice class here which I've called have an object of synth voice called my synth that's actually outputting through the speakers okay so we have a different kind of situation here because we have kind of three sides of the plug-in that we need to really kind of route our variables from into so we have the plug-in processor where we're doing all of our hard core DSP processing then we have the plug-in editor which is where we have our graphical elements and our UI elements sliders and dials that we're going to be controlling and when we control those parameters we want to relay all of that information to the plug-in processor now we have this third part the called synth voice okay and some of the DSP processing is actually happening here and this function that we call friender next block so what we need to do is we actually need to be able to pass these variables in these parameters around between these three classes and I'm going to show you how to do that and then on top of that what we need to do is we need to relay have a way that we're able to relay this information to the host so the host is our D aw could be able to in or logic and so if you've ever worked in a DA W before you know that sometimes you want to make automation so if you want one of your parameters to change over time you need to be able to do that in the da W and that the W needs to be able to recognize that I'm gonna show you how to do that as well okay so before we get started I just wanted to let you know very quickly that we've got a discussion group if you haven't if you're not aware of it just yet it's called it's on a platform called discord and so we have an audio developer discussion group we have about 70 developers in there now and they're all there of all different levels and all different areas of expertise and it's just a great place for developers from all over the world that are interested in audio and DSP to kind of come together and trade ideas and to ask each other questions help each other out and so if you haven't joined yet I'd love to see you there and come and join I'll put the link below also for people that are just trying to get in touch with me the messaging system on YouTube is a little bit crazy so I'll come just find me on any of the other social network platforms I'm on Twitter at all your programmer then on Facebook and Instagram at the audio programmer so come and come and say hi so let's go ahead and get started so we're gonna go ahead and start with the plugin editor side so we're going to start with the UI elements so this is going to be kind of a I think this might be a bit of a lengthy tutorial but I think it might be better to do it this way because inevitably as I come up against problems like I think I'd like for people that are just getting into development or just kind of starting to see how I kind of think through the problem and you know how I try to just kind of work my way through it so I think that might be a little bit more useful than if I just kind of give you a super edited version where I just kind of tell you what to do I don't think that's very useful so I hope you find that useful if you do or if you don't just leave me a comment below let me know what you think okay so we're gonna go ahead and get started first thing that we're gonna do I'm gonna refer to my API quite a bit in this tutorial so I hope it's not too late for you so we're just gonna go to the plugin editor header file okay and a lot of this stuff is stuff that I plot that I've already kind of covered in class pass tutorials so I don't want to harp on it too much but I'll try to cover it briefly as much as I can okay so kind of nervous I hope I don't mess up so first thing that we're gonna do is we're going to add a slider for our attack so we're just going to start off with by making an attack slider see if we can get that working and kind of routing through in the right direction so I'm going I'm gonna make a slider that's called attack and then what we're gonna do is we need to inherit from the slider listener class listener so I'm just inheriting here from the slider slider listener class and that's to relay that if the slider value gets changed we're just going to relay that information over to the processor so that it knows that we're making a change okay so in here and private I'm just gonna declare a slider I'm just gonna call it a tax slider for now so then I'm going to create okay so if we go back into our header file if we go into our slider listener class as we coincidentally happen to be on you'll see that it has a pure virtual function and we know it's a pure virtual function because we have this equals zero so what that's what this means is that if we're inheriting from this class we need to actually declare this somewhere in our in our in our implementation so I'm gonna just go ahead and do this void I think it's called slider slider value changed you changed slide our winner and we've got a pointer to our slider we're going to call this we're gonna call override here because this is a pure virtual function and we're going to override that with our own implementation so then we're going to go down here we're going to go void juice synth framework audio processor editor slider so here we're just going to implement this okay and then I can just say slider or pointer slider and I'm just going to leave that blank for now okay so I'm going to try to build this I don't know if it's actually gonna build at this point but okay cool so we got build succeeded I'm gonna frequently do that just to make sure that I'm kind of keeping on track I'm just gonna leave the window size the same not messing around with that for a while so we called this a tack slider so I'm gonna start declaring some things here a tax slider so we're gonna need to set set the slider style so it needs to know what slider style it is so we're just gonna call the slider slider style and then linear or vertical I think we're gonna call it autocomplete is testing me see and if I know what I'm talking about then we got a tax slider set range I think it's called oh wow it's really not helping me so I'm just gonna go over here to the API here just check this out so here's our slider so I think it's called set range set range and we have your double new minimum the maximum so so set range I'm gonna put this 0.1 for the minimum and then for the maximum I'll put it at five thousand which is five thousand milliseconds okay then what else here I'm just gonna refer to some notes here so we need to set the text box style set text box style so we could say slider text box well it's really not helping me today is it I think it's called text box below I'm just gonna make this read-only and then I'll just make the width of it I don't know 20 pixels and then the height of it 10 pixels maybe okay then what else we got here we did set range we're gonna set an initial value attack slider set value I'm just going to put it at 0.1 we need to add it and make it it and make it a child of our component so a text slider this so this is stuff that I've already covered too - in past tutorials and stuff so I need to make make it a listener adlistener mmm do I got the right and listen to this so I'm just gonna build this real quick make sure I got this all all right so waking up okay cool build succeeded cool that's fine I'm not gonna worry about really the where the UI elements are placed too much because I can worry about that in a later tutorial because I think that I think it'd be good just that discuss that for one full tutorial so we're gonna set the bounds on this and then I'll just put this at 10:10 and then the width will be I'll just put it 20 the height output at 50 and we'll just do it like that okay so was there anything else that I've missed here so I've drawn it I've made it visible okay so what I'm gonna do is I'm just gonna compile this real quick make sure that it's actually showing up and here's our host okay then I'm just going to double click on this and then if I if I bring this in here so here it is I'm gonna make it just a little bit bigger it's a little bit bit small right now so let's see I will make this a hundred and then I'll make it I'll make it 40 wide okay just try that now just make sure that we have a little bit of space to work with so here we go that's a bit better okay not gonna worry about I'm not gonna worry about this here something I don't I don't really want to harp too much on it so I'm just going to take this out for now okay so that's great so now what we can do is we can have a look at what we need to do to get this into the processor first okay so from now what I'm going to do is I'm just going to create a public variable don't need to cut I'll just call it float attack time okay just for now what I'm going to do I think I'm going to handle this differently if I remember right but for now I'm just going to set this to a variable and so I can pass so I can this information on okay but I think that I'm gonna actually handle this differently through the through the value tree but we're just gonna check it we're gonna check it out here so we need to say if if slider is equal to attack slider then we need to we need to set the value of attack time to our to our slider value so we can do that the access to the processor okay so we just have the processor object here I've discussed this in a past tutorial in case you don't know what I'm referring to so so I can say I can I can actually say processor dot attack time equals attack slider I think I need to use the arrow operator here because it's a pointer get value this sounds sounds right this sounds right so let's oh it's not a pointer okay so do it just do this let's try that again okay so that compiled fine and what I'm going to do is I'm just going to I'm just going to actually go back over here to the processor and then I'm going to go to my attack time and I'm just going to make sure that that's actually that's actually coming through okay I'm going to actually do this in my audio thread I know this is a no-no but I'm just I'm just doing it just strictly for the reason of just making sure that the value is actually coming through so we need STD C out attack time STD and wine so what we should see hopefully is when I modify the slider hopefully it should modify the attack time so let's hope that I don't mess this up so it's a weird value because I haven't I haven't initialized it yet but here we go okay great so so it's fine as you can see it's doing it so I had that weird number there at first because I haven't actually I didn't actually initialize it at first but I'm not I can actually do that here in the constructor okay so if I use an initialization I could say attack time zero point one F and that should be fine I think okay we're just gonna make sure that that initialize is fine okay I'm gonna do this again just go back here so now we have it initializing to a nice value here and then you can see as I move the slider up and the slider down that it is correctly modifying the value which is cool but useless because I don't think that we're actually gonna use it anyway but now I can get rid of this so all my DSP guys can finally breathe again because I can't have cam message in the in the audio thread so that's fine okay great so now I think what we're going to do is we're going to go ahead and take a dive into the deep end with the audio processor audio processor value state tree audio sir I always forget this audio processor audio processor value value tree state I always get this name confused so audio processor value tree state okay so this is gonna be fun it's gonna be fun to implement always have a it always seems to be an adventure when I implement this so hopefully we can we can get through this without too many hitches so what we can do is we can say audio processor value tree state we're gonna do a an object here I'm just gonna call this tree okay and I think it doesn't need to be a pointer oh man terrible I'm probably terrible for not knowing this I'm just gonna go ahead and initialize it here and then go back if I need to if I need to change it so I can just say tree here I don't think it needs to be a a pointer and wouldn't make sense to so processor to connect to is actually a pointer to this okay to this processor and then I could make this a no pointer because we don't need to worry about a undo manager at this point oh no it's giving me an error what's going on here is it gonna go away ah yes success great fantastic so so far so good I haven't gotten stuck yet okay so that's fine so now we need to actually create so what we so what we need to do at this point is we actually need to link the the purpose of the audio processor value tree state class is to link up values that are happening between the slider and the processor and then to relay all this information to the host and to do this kind of an elite in a neat package so we have this we have this function here we need to do create I feel like I'm gonna mess up here I hope not so it's gonna be tree dot create and add parameter ok so then I'm gonna just call this attack and then I'm going to call this attack with a capital and attack with the capital again this is all stuff I went through in the gain slider tutorial just in case you're wondering where I'm getting all this from so I don't want to take too much time on any one one kind of thing ok so here we need to create a normalizable range object so normalizable range this needs to be a float just gonna call this attack program and then I'm going to make this a range between 0.1 and 5,000 and so what I believe this does I'm a little bit confused about this but I think what it does because I think some hosts when they're notifying to the host I think that it needs to be normalized between a range of 0 and 1 so I think what it does is it takes this range that I'm normally have of between 0.1 and 5,000 and is remapping it to zero and one so if I'm wrong about that somebody let me know so I can so I can kind of correct that so here in my normalizable range part here I can just put a tack program and then default value is 0.1 float and then these last two don't have to be anything so I'm just gonna put them to null pointer and null pointer okay I'm just gonna try to build that see if it's going to complain it or not I think we're okay okay so so far bill this has succeeded that's fine and then what we need to do is we need to go to the editor and then we need to do this on the other side remind me how I need to do this oh boy I hope I don't get stuck here so creating that parameter because I need to let it know so I need a way to get to the actual ID of the processor so I need to actually let let it know that the slider that I'm controlling is controlling this parameter and I can't remember how to do that oh here it is slider attachment that kind of makes sense so this is what we need we need a slider attachment so here I can say so audio processor value tree state slider attachment and then I'll just call this slider attach slider slider tree okay and then we need to go to the editor and then how is this handled let me try to remember so let me go back here what does that call it again so go slider tree tree okay so let's let's just go to okay so if I remember right I need okay what's going on here okay so this needs to be doesn't this need to be a scoped pointer this needs to be a scope - pointer doesn't it so let me go back here I'm just gonna comment this out for a second yes because we need to declare it as new slider tree equals new okay so what I can do is I can use a skipped pointer here once again this the stuff that I've gone through and my in my past tutorials let me see if that builds I just want to make sure I got the syntax right build failed so let me see here let me think one second I'm just gonna actually look at I'm gonna actually cheat and actually look at my one of my other one of my other files here so audios so let's go to pointer slider value so why oh these are capital all these little things okay so let's try that again okay so that's fine okay so let's go back to our editor now so I believe this needs to say slider tree equals new audio processor value tree state slider attachment and then we need a state can state to control so the state to control is processor dot tree the parameter ID we call the tack and then the slider to control is attack slider okay so let's just try this I hope this works so it's linking so so far so good okay so now what I'm gonna do just to make sure that this is so so just to remind you what this is doing this is actually taking and it's linking the the parameter that we've got with this slider and it's linking the is calling it attack and it's linking it with our processor side okay and on this on this value here that we call that we called with tree create an app parameter okay so now what we could do is we could go let's see we can actually go down here we could do I'm gonna do this again and let's see I just want to make sure I kind of want to make sure that this is happening that this is working properly but I'm not gonna worry I'm not gonna worry about that for now because I'm afraid that I'm gonna get tripped up okay so and I don't want to get tripped up so okay great so now listen so I feel pretty confident that we've got the editor side and the processor side linked up properly through the value tree so now what we need to do is we need to have a way to link it from the processor so we need this value so we so we need to get the value from this parameter idea attack and then we somehow need to get that into here okay so it needs to get the attack time from the slider and it means to actually put that in here and then it needs to be able to modify our attack time on our ABS our parmi so so what we need to do that is we're going to make a we're going to make a new method here I'm gonna do it right below this can play sound I'm just going to call it get program so I'll go void get program now the reason the reason that I'm doing this is because I basically need a function to call in my process block wherever my process block is okay so I need a function to call in my process block where it will actually get the value from from my from my value tree and it'll actually relay it over to myself voice okay so the way that it the way that it does this and this just happens to be because I've done this before it's through its through a pointer so if we go if we go through our audio processor you Tree State if we scroll down here we've got this parameter that says get raw parameter value so what I can do is I can say basically get raw parameter value I could put attack in here and then what it does is it returns a pointer to a floating-point representation so to basically give me the floating-point number of whatever that value is okay so that's what we're gonna that's what that's how we're gonna get the value from from our or our parameter in our tree over tooth synth voice so when I have this this function called get program I'm going to actually call this a float pointer attack okay so that's why I'm sending that to a that's why I'm sending that to a pointer there okay so what we can do here Oh was it was it gonna be an error let's see is it gonna okay it's just a just a false alarm here okay so that's cool so now what I can do is I can actually take this I'm actually going to just remove this attack time and I'm gonna put this here I'm just gonna say here so what I could do to denote dereference not do you know dereference the value at the location that attack is pointing to is I could just use that star and and call that attack now one thing that I'm gonna note here if I if I just said here m1 that set attack it's not gonna come up with it oh yeah you're gonna see that it's that it's a it's a double so I'm not sure if I need to do this but I'm just gonna cast this as a double just in case okay so I've just got because this is a float okay envelope one dot set attack takes a double as an argument so I'm just casting this as a double I'm casting this float pointer as a double just to make sure that there's not going to be any sort of communication problems there okay so now what we need to do is we need to find a way to actually get this and to relay the information from the plugin processor okay the way we do this is through a little trick that I can't I can't take credit for it's a bit of code I think I might have seen it in the plugin example maybe or maybe in my friend Leon Tenon's example of an of an FM synth that I saw a while back but basically what he does is he uses a dynamic cast in order to a dynamic cast of synth voice and when the voice returns with the dynamic cast being true then basically it relays the information and you'll see you'll see what I mean in the second here so let me see if I can get this right the first time hopefully so so what we're going to do is we're going to go we're going to make a for loop we're gonna call it so we have the synth voice called the synth voice object called my synth so I think it's getting numb voices and then I plus plus I'm just going to compile this real quick just make sure it's I've got the the function right that I've remembered it right so that's fine okay and then what we're going to say is if the voice is dynamically cast as a synth voice then relay the information okay so if my voice are my synth is this right now synth synth voice what I call it my voice so we have this pointer it's called my voice we want to make sure that it's dynamically cast as a synth voice pointer okay so if my voice equals dynamic cast and then here we need to put in the type of cast that we're talking about synth voice pointer and then this is then we need to get the voice itself my synth get voice and then the voice that we that that were actually that we're actually pressing okay so that's a little bit confusing kind of confuses me as well and to be honest this it's a piece of code at oh I hate to say this but I don't fully understand it but I can see that it works and if somebody has a really good explanation for this I'd love to hear it but it's a we'll admit it's not a piece of code that and it seems that it's not a piece of code that this understands as well because I'm not oh yeah this is just one of the other things you can place the parentheses around the silence this morning so that's the way that we do that here one thing here it because my muscle reflex automatically put a double equals in there do not do that or else it won't work properly and you'll get a weird error so make sure that's not a double equals okay so it's just saying if my voice is dynamically cast as a synth voice object which it would be hopefully then get yeah so if it's if it's cast as a synth voice then get the voice and then from there we get the parameters okay so that that kind of makes sense in my head now and I hope it makes sense to you as well so now we need to go back into synth voice and we need to call up get params so my voice this is a pointer so we need to use the arrow operator there rather than just my voice guitar am and then here is where it gets a little bit kind of tricky because you're like okay well what do I put here and remember when I said that we have this get raw parameter value that's a float pointer there so that's what we need okay so we need to put tree dot get get raw parameter value okay and the one that we need is by the ID we just call that attack and I think that's right I'm just gonna trust my instinct here and say that that's gonna build a fine so I think that this is all right and I think it's all linked up properly so I'm just going to check now hopefully it will not blow my hairs out because that would not be good okay okay so so we've got sound which is good it hasn't blown our ears out that's a great start okay so if I put this up to 5,000 yes it works oh I can't believe I got it right working right the first time I cannot believe it okay okay so you hear that it didn't initialize properly we can fix that that's cool so that's no problem but you can hear that it actually works I cannot believe I got this working the first time properly that's so that's made my day yeah so so so now we have our attack okay so now we we heard that it didn't initialize properly okay so I'll just show you a demonstration of that again really quick so we just need to take a look at that I think that should be an easy fix but we'll just take a look okay so if I plug it in and then I'm not gonna touch I'm not actually gonna touch the UI because the UI if I open the UI it might relay the message of what the correct parameter is but I don't want it to do that just yet so let's see what it what it sounds like now okay so it started really quick and did it did it initialize properly yes so seeing the initialized probably that time okay and then we got the parameter that's fine okay so I'm just going to do this just to make sure that it initializes properly so if I go into synth voice I think if we go here and we just make a real quick constructor I think I think that this will make sure that it that it actually initializes properly so what I could do is I could just go oh I don't have a I don't have a separate I don't have a separate variable that I've that I've done here I've done it I've done it just in here hmm-hmm-hmm now do I need to I don't I don't know if I need to it seemed like an initialize let me just try it one more time just to make sure that it initializes properly and then if it doesn't initialize properly I'll go through the trouble of taking this and taking the the pointer I'm and making another variable but let's just try it again here real quick okay and then yeah and initializes fun okay great so let me just pull this here just see make sure it works again okay that's great okay so shall we quickly while we're while we're here shall we just shall we just try to set up the whole adsr right quick why not no so this will be just a little something at the end of the video here so let's let's just let's just set everything up I don't actually I don't know it's might take a little bit of time I'll do one more I'll do one more so just just so just for kind of you know just to kind of really emphasize emphasize it in so we'll go ahead and we'll just kind of start from the beginning again okay just to just so we can like emphasize the lesson of the day here so I'll make another slider here we'll call this release slider okay then we'll go to the plugin editor and I could probably make this piece of code a lot more elegant but I'm not going to worry about that for now so processor I don't even know if I need to do this because we have this actually actually happening in the tree but I'm just going to do it just so just for the heck of it I guess release slider get value okay I need a variable called release time on my plug-in processor float released time don't actually think I need those two variables there but I'm just gonna put them there because did that the first time and I don't want to mess this tutorial up this late in the game so let's let's see so now I need to go to back to my processor here and we need to go back up to add another parameter so we can just call tree create and add parameter and then we can just call this release and then I'll just do it with a capital and with a capital again and we'll do a release program and then I'll just create that here so we'll just call this normalizable range don't like to just copy and paste because I want to feel like I'm in the matrix like that so we'll just make this the same thing as the attack I think five thousand zero F and then default value will just be 0.1 F and then this will be a null pointer again and they'll pointer again okay that's fine so that looks good and then where are we so now we need to change or get programs so this should be float attack float release okay then we could just take our release time I could just set this to cast as a double we're going to dereference the value that releases and then we need to go back to our processor we need to go back down to our process block because that's where we're calling get program so we need two arguments here so we got tree so we got them one for our attack then we got get raw parameter value and then just call this release and then we haven't created a slider yet so we need to create a weave we've got to release slider that we've created we just need to set the parameters now so we can call this release slider set the slider style slider slider style linear vertical then a release slider set range release slider set value 0.1 F the release slider we need to add it as listener this add and make it visible release slider and then we need to take care of our value tree here ooh one second here so we need let's see do I need to separate objects here hold on a second here so just want to make sure I get this right so we got scopes pointer do I need to separate scopes pointers here mmm-hmm I'm going to just know it's going to need to separate ones because otherwise it's gonna be just going to the same same thing right I'm going to just try it as one but I think that it means yeah cuz it's gonna be setting it equal it's gonna be setting it equal to two was it was it saying here oh I forgot a t yeah you can't set it equal the two things right I'm just gonna try it but I'm just sesor slider attachment processor top tree release slider mmm oh boy I really feel like that needs to be two separate objects there I'm going to I'm going to make it two separate two separate objects to separate pointers here so I'm just gonna call this let's call this attack tree and then I'm just gonna do the same thing I'll call this release tree I just hope this doesn't mess up this tutorial at this late point so release an attack set slider style so what's what's going on here is this not right okay it's giving me an error so where are we here okay yes that's what I so this needs to be like that okay let's try again okay so okay cool so now I'm just going to go back to my processor block just make sure that I have this all the initialized correctly sestri get wrong okay so that's fine go back to here so this looks alright so okay here's the final check here so hope really hope this works and if it doesn't work I'm not going to do this tutorial against I hope I hope you guys can forgive me for not getting it all right if it doesn't work out okay then blow our ears out good okay seems like an inch in and initialized correctly which is awesome okay oh I didn't draw it I need to draw it I haven't drawn it yet so let's go back to the editor so we just need to set I'm just gonna make this static I can come back to this later or we can do like a more dynamic GUI but this is just gonna be a quick and dirty so we could put it let's say I don't know four sofas forty across ten so that's fifty so I'll just make this 6d ten I'm just gonna put it kind of anywhere sorry about this I just want to get this done and it set you guys off as soon as possible here so if you stuck with me this long I'll give you I'll give you kudos for sure because this is definitely a test of endurance so um I'm sure sure some of you probably have my voice on fast-forward right now so here we go that's try and then did after all okay so that didn't draw it all the way across the screen so let's try it now okay so let's try the attack okay now let's try the release yes it works I can't believe it can't believe I got it all working pretty smoothly nice nice nice nice oh great okay so I'm gonna end it there while I'm still ahead and I've to have it I haven't messed it up so I've really hope that you enjoyed this tutorial I've really put a lot of work into it so if you can't take the time to to like and say something nice because I've really enjoy hearing nice things said about the hard work that I'm doing here so that's it's always good to hear and I'm gonna end it here and next time we'll add some more I'm not sure we're gonna add some more or I can just maybe start going into more of the UI stuff just kind of how to dynamically do that I think I'll probably lean towards doing that since you don't want to see me making more sliders and dials and stuff so next time I come back I'll probably have a lot more parameters kind of laid out and that we can talk about UI and dynamically resizing and how to make a you an effective UI so I really hope you enjoyed this and I will see you next time
Info
Channel: The Audio Programmer
Views: 5,606
Rating: undefined out of 5
Keywords: Juce Framework, framework, juce audio, creative programming, audio coding, vst development, vst, software development, c++, juce, plugin development, audio programming, creative coding, digital signal processing, dsp, plugins, ableton, max msp, parameter, gui, ui, audioprocessorvaluetreestate, computer science
Id: PaKXRm6RZF4
Channel Id: undefined
Length: 56min 23sec (3383 seconds)
Published: Tue Dec 05 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.