Welcome to Our Next Tutorial in the Free JUCE 6 Tutorial Series

Welcome to our JUCE 6 Tutorial FREE YouTube Tutorial Series and this Tutorial 01.  In this Series Josh Hodge will introduce you to JUCE 6 and how to use it to build your own Audio Software and Plugins.  Along the way, Stu Last will be adding tips, explanations and alternative approaches in our new Tutorial Supplementals.  We’ll also be adding a transcription of Josh’s YouTube Tutorial to really help you get to grips with the JUCE 6 Framework.

In Tutorial 01 Josh explains how JUCE 6 uses Namespaces and Stu takes some time to go into more detail about what namespaces are, how they are used, and why JUCE 6 has taken a new approach to using Namespace.

How to use these tutorials.

Stu recommends watching Josh’s YouTube video first, and working through the examples with Josh.  Then jump on over to Stu’s Tutorial Supplementary and read the additional material.  You’ll find the Tutorial Supplementary and Transcription Below.

Transcription

Note that time indexes have been added to the beginning of each paragraph to aid in navigation around the the YouTube video.

— Transcription Begins —

Josh Hodges –

(00:00) “Hey what’s up everybody, I’d like to welcome you to another JUCE tutorial. In this tutorial I’d like to talk a little bit about the JUCE namespace. In JUCE 6 the jJUCE team have decided to make it mandatory by default that you use the JUCE namespace before you instantiate any JUCE classes or objects. Now the question is, what does that mean for you? And I’m going to show you in this tutorial.

(00:25) So let’s go ahead and create a new JUCE project so I’ll just do that by going up and saying “File -> New Project” and here we have our new project. I’ll just create a plugin, we can just call this “samplePlugin”. I will create it and put this on my desktop. Now I’m going to have a new project here and it has all my files. What I can do is go up to the setting and I’ll show you this new setting here. Down here it says “Add ‘using namespace juce’ to JuceHeader.H and this is disabled by default, and I’ll show you what this means right now.

(1:10) So let’s go ahead an open this up in our IDE, so we’ll jut click this centre button, and this will open our project up in XCode. And here we are. So normally in a JUCE tutorial (if you’ve seen any of my JUCE tutorials in the past), we can just instantiate a JUCE object just by typing the name of the object. So for instance if we add the Slider class we can normally just say `Slider mSlider;` like this and we can just compile and it would work.

(1:45) But as we can see we’re going to get a build failed, and it says (the error is) “Unknown type name ‘Slider’; did you mean ‘juce::Slider’?” And this is what I mean by “Using the JUCE namespace.” In front of any JUCE objects or in front of any JUCE classes that we’re instantiating we would need to put “juce::” in front of this class. So lets go ahead and try to compile again. We will see that we now get “Build Succeeded”.

(2:16) Now the question is why have they decided to do this? Does this not make things more complicated. The reason that they’ve decided to do this is that, sometimes you would would get name collisions when using multiple libraries. So lets just say for instance, in a hypothetical scenario, we had two UI classes that had a class called “Slider”. When the codes trying to compile and we don’t have any namespace in front of this “Slider”, if we have two UI “kits” that are both using the class called slider, it wouldn’t know which “Slider” you meant Does it mean the “JUCE Slider” or does it mean the “Slider” from this other library. So that’s the reason why they have made it where you need to put the namespace in front of it and specify that this is the JUCE::Slider.

(3:17) So I’m going to show you a few little tips to help with longer names. One of the things that I noticed when I first started out when you have these really long namespaces that get very long to read out. So for one example, let’s say we have std:unique_ptr mAttach1, lets add a couple like this and I’ll just name them ‘2’ and ‘3’.

(4:14) I remember when I was first starting out that this looked very long and very confusing to me. So one way that you can abstract this out is by using the “using” keyword. So we can do something like this using Attachement = juce::AudioProcessorValueTreeState::SliderAttachment; and we can make Attachment mean this long thing here. Then what I can do , within the scope of this code (so within this header file), anywhere that it says juce::AudioProcessorValueTreeState::SliderAttachment" I can now just replace that with `Attachment` like this. And so sometimes that helps to clean up some of the code as well.

(5:09) One thing that I’ll say is that, in terms of best practice, it is best practice to put the JUCE namespace in front of objects to prevent name collisions. For smaller projects or smaller plugins where you’re not using any sort of external libraries it’s probably okay, but in general it’s best practice to use the JUCE namespace in front of these objects.

(5:35) Sometimes you’ll see this, like a `using` keyword, so `using` some keyword = this long bit of nested code right here. Another way that you can do this, or another way that you’ll see in some code bases is something like this where you can use `namespace juce` like this and then you need to put closing parenthesis like this. Now anything that’s in here that’s supposed to be a JUCE object you ow don’t have to put `juce::` in front of it. Now if I compile this the build we fail because I need to do the same thing for the ‘cpp’ file as well.

(6:31) In general, it’s I guess it depends, but in general I wouldn’t advise you should really do this. Some codebases I’ve seen have really nested namespaces and they’re very, very long, so you have namespace juce and and sometimes inside that you have some sort of other namespace. What this basically means is that, anything in here that has a JUCE object that it will automatically put the ‘juce’ namespace in front of it. Let’s try to build here and make sure that this build succeeds, and we’ve got a fail “unknown type name”, so we just need to put “juce::” in front of this as well and now we should get a build succeeded, and now we’ve got build succeeded just to show you that this works.

(7:38) Another thing that I’ll show you (so lets just go out of this back to the beginning, like this), is that another thing you can do is actually enable the “using namespace juce”, like this. Then we open up in our IDE and this will bring you back to the “old way” where you just instantiate without need to specify the juce:: namespace. But I would say in tutorials moving forward what we will look to do is actually look to do this in the way that I’ve been told is the best practice which is to use the “juce::” namespace. So moving forward we will now do it like this and `juce::Slider` rather than just “Slider”

(8:37) So those are a couple of tips to give you some help. I hope that this was helpful for you. If you have any questions or you have any better suggestions please leave a comment below, and don’t forget to subscribe and drop a like on there as well. I’ll see you next time”

— Transcription Ends —

Supplemental

In this lesson Josh covers some aspects of namespaces in C++ but it is worth looking at the detail of the lesson and C++ namespaces in general to get a better idea of why they are used, how to use them, and some of the best practices seen in C++ today.

Let’s start by looking at what a namespace is.

Namespaces – an introduction.

C++ is a fairly established language that has been round for a long time and is based on the language C, which has been around even longer. C++ has evolved over it’s lifetime, with one of the features being that of “Namespaces”. Namespaces in C++ and in many other languages are a way to collect blocks of code together and give that collection a name.

Think of it this way – if you have a street on a map, the individual houses would be the blocks of code (objects, structure, etc) and the street name would be the namespace.

Why namespaces came into being

One of the things you’ll encounter as a developer in any language is the use of libraries of code. This is code written by somebody else that is provided as a sort of toolkit upon which to build other code. Effectively, a library allows us to re-use (or even create) tried and tested code so that we, or other programmers don’t have to reinvent the wheel. The JUCE framework is one such library that handles the heavy-lifting and/or commonly used code in Audio Programming thereby letting the programmer focus on creating something new, interesting and, hopefully marketable. Let’s face it, it would be crazy to have to keep redefining commonly used code each time you wanted to build a plugin.

The problem comes, though when you start using multiple libraries, or even your own code. What if more than one library contains the same object name, static method, struct etc. How will the C++ compiler know which one you are referring to, unless you’ve been specific. Take, as an example, the number Pi, a pretty important number when it comes to generating waveforms. C++ has a library, cmath, which defines a constant for Pi. JUCE also has a constant for PI. For the purpose of demonstration, let’s assume they are both called PI. We’ll also assume that you want to use math constants from both cmath and juce.

In your sin wave generator, you use the JUCE Pi in the formula. It makes perfect sense to you because, at the time of writing, you know which Pi you mean. But what happens if you have to work on the project again in a few months time? Will you be clear which P you intended to use? Would another programmer instinctively know which Pi you intended to use. In a situation such as this, where there is no way to know which Pi you intended to use. The compiler is wise to this, and, where there is any such ambiguity, will flat out refuse to build. After all, it’s a program and until software can read our minds (a truly terrifying concept), the compiler will never know which Pi you are thinking about.

To use our street address analogy, if you have 2 streets, both with a house numbered “1”, how will the post man know which house to deliver to unless you provide additional information (such as the street name) to make the address more specific.

Specificity

This is where namespaces can solve the problem by adding “specificity” to our code.

It’s worth noting at this point that, if your working in a language such as C++, you are probably beginning to think about yourself as a software engineer. Engineering is all about specificity. If you look at an Aston Martin DB9, each nut, bolt, wire, resistor, basically every part has been selected for a specific purpose. A bolt of a specific size, tightened to a specific torque, machined to specific tolerances and placed in a specific position will do one job, and it will do it extremely well. This is as true of software engineering as it is of any other kind of engineering. Being specific adds clarity to your code.

Getting back to namespaces and our Pi analogy. It may be, for drawing a circle in the UI, that the cmath definition of Pi is defined to just the right number of decimal places and so this would be the perfect fit. When generating a sine wave, it is likely that the JUCE definition of Pi is more appropriate, and that should be the one you use. By adding the namespace (cmath or juce) you are declaring in your code the specific definition that you’re using, and this is readily apparent to the compiler (which means your code will build) and it’s clear to anybody else reading your code or developing the software alongside you. In short, Specificity adds clarity and intent to your code.

The “using” Keyword

This is where we might get into some heated discussions about the pros and cons of using the “using” keyword but I’ll try to stick to purpose rather than opinion This keyword gives us a tool to shortcut our typing, that’s all. When the compiler compiles, it will still seek out the appropriate code declared in “using”, add it the .h and/or .cpp file and then, at a later part in the process, optimise the code as best it can. If you could open up and read the files that are output from the compiler, you wouldn’t see any “using” keywords, or even recognise the code. The reason the keyword exists is to make a programmer’s life easier and to use “natural language” to create software rather than hex codes and binary. In short, the “using” keyword is a bit of a shortcut.

The “using” keyword, as Josh alludes to in the video, gives the programmer the opportunity to inform the compiler which libraries the compiler in for a particular block of code, whether that is a function, constant, struct or class. As advanced as computing is getting, guessing what a programmer is thinking is still, thankfully, outside the capabilities of a compiler.

Scope of “using”

The “using” keyword has scope. That is to say it is sensitive to where it is placed in the code. If you place it at the top of a .h or .cpp file, the namespace will be used everywhere in that code. If, however, you place the namespace within a block of code (for example within the ‘{ … }’ surrounding a method), then the namespace will be used only within that block. if you place the “using namespace” within the ‘{ … }’ of the class then that “using namespace” will be available to the whole class.

#include <iostream>  // This is an instruction to the pre-processor to grab the code from the iostream class(es)/header(s) and inject it here using namespace std;   //this tells the compiler to look in std for objects, methods etc. It is in the outer scope of the file, so will be referred to everywhere void foo() {

cout << "This cout will also work because the scope of 'using std' is above both the functions. \n\n";

} int main() {

cout << "This cout is found in the std library, which is where the compiler looked for the cout function. \n\n"; foo(); return 0;

}  

Note that in this code snippet, the “using” statement is outside of all code blocks, so has scope over all code within this file.

If we wanted to use “using”, but be a tad more specific, we could change the scope of the “using”, by including it in a code block.

#include >iostream<// This is an instruction to the pre-processor to grab the code from the iostream class(es)/header(s) and inject it here void foo() {

cout << "This cout will also work because the scope of 'using std' is above both the functions. \n\n";

} int main() {

using namespace std; <//this tells the compiler to look in std for objects, methods etc. It is in the outer scope of the file, so will be referred to everywhere cout << "This cout is found in the std library, which is where the compiler looked for the cout function. \n\n"; foo(); return 0; ,/p> }  

In this example, the “using” is limited to the main() function code block. In the foo function, we’re relying on the compiler to guess where cout is located, but because the scope of “using namespace std;” is limited to the main() function, the compiler won’t know where to look, and we get a build fail.

Using ‘using’ to create Aliases for types.

Now that we’re a little more comfortable using ‘using’, we can take it a step further. Before I go further, though, let me just explain that a type can be a basic type, such as an int, or a complex type, such as a class or struct. Josh demonstrates this really well in the YouTube video, but another example is shown below.

#include <iostream> // This is an instruction to the pre-processor to grab the code from the iostream class(es)/header(s) and inject it here using namespace std; using wholeNumbers = int; int main() {

wholeNumbers number (10); cout << "This cout is found in the std library, which is where the compiler looked for the cout function. \n\n"; cout << number << "\n\n";

}
 

Whilst this is an admittedly somewhat contrived example, and absolutely useless in this context, it does show that you can create a measure of readability in your code by creating an alias for a type. So when Josh proposes using attachment = juce::ProcessorValueTreeState::SliderAttachment as a way to create readability in your code, it is a valid way of using “using”. The compiler will simply change each reference of attachment back to it’s full namespace path and type, before processing the code, optimising it and spitting out a working program. Again, this use of “using” is merely an option to make the code easier to work with.

Remember, that this use of “using” can also be scoped to specific blocks of code.

An alternative to using for creating Aliases

There is another way to create aliases in your code, when dealing with types: The “typedef” keyword. Syntactically, this may appear to be more obvious as to what you’re trying to achieve. After all, it’s not a huge stretch of the imagination to see that typedef translates to type definition.

So, to switch out our previous code to use typedef instead: #include <iostream>// This is an instruction to the pre-processor to grab the code from the iostream class(es)/header(s) and inject it here using namespace std; typedef int wholeNumbers; int main() { wholeNumbers number (10); cout << “This cout is found in the std library, which is where the compiler looked for the cout function. \n\n”; cout << number << “\n\n”; }  

In this case the two different keywords, “using” and “typedef” are clearly performing different roles, although this is, once again, a somewhat contrived and wholly useless example. Let’s something that, at first glance, could be seen as a little more useful.

#include <iostream> #include <map> #include <string> typedef std::map<int, std::string> rankings; int main() { rankings raceRankings; raceRankings.insert(std::make_pair(1, “first”)); raceRankings.insert(std::make_pair(2, “second”)); raceRankings.insert(std::make_pair(3, “third”)); std::cout << raceRankings[2] << “\n\n”; }

This compiles just fine, because once again we are just talking about an alias as a convenience for the programmer. The compiler will happily replace all the mentions of “ranking” with the full std::map<int, std::string>; whilst pulling together all your code, optimising it and converting it into a lower level language that the computer can actually make sense of and use.

So why all the fuss about not using “using”.

At first glance it does seem to make our jobs as programmers much easier to use “using” as a shortcut and to use these type aliases. But consider the following scenarios:

namespace scenario

You have a JUCE project, which uses the juce namespace at the top of all it’s files. Part of this project also uses a bespoke synth class form the namespace myBiz, your companies own syth class with more functionality. You create a project, and in the process of writing it put “using namespace myBiz” at the top of each file. A few months later, whilst working on another part of the project, a colleague requires something from the JUCE library, and ticks that little box to add “using juce” at the top of each file. Now the build fails because the compiler has two choices of synth class. Much debugging ensues.

Alias scenario

You’re working on a team of developers in a busy software house. At the inception of the project lots of type aliases have been defined in the header files. Over time, the files have grown and now need debugging. Do you have the time to keep scrolling up to the top of the file to remind yourself of the typedefs/using aliases, or would it actually be quicker to know straight away, wherever you are in the code, what specific types you’re using?

As mentioned several times in this document, “using namespace” using “using” to create aliases, and “typedef” are tools were created to make the programmers life easier. But, they are only useful until they stop making the programmers life easier.

Your Options

You can push ahead and use “using namespace” and using “using” and “typedef” for type aliasing at the top of your file, at the highest level of scope, and hope you don’t encounter any namespace clashes.

You can use “using namespace” and using “using” and “typedef” judiciously, and keeping it to the most limited scope possible, thereby keeping definitions and namespace shortcuts as close to the point they are being “consumed” in your code. This will make a bit easier to track down compile time bugs and the dreaded runtime bugs.

You can take the time to get used to typing and reading fully qualified namespacing in your code (ie std::cout). It is amazing how quickly you’ll become accustomed to it, with the added bonus that you will type in exactly what you mean, and other readers of your code will be in no doubt about exactly what you meant when you wrote it.

The reason code like “using namespace std” is frowned upon, and the best practice is to use fully qualified namespaces in your code, is that it is specific and clearly states the intent at the point that line of code would be executed.

A word on “namespace”

In the video, Josh uses the following as a shortcut to the JUCE namespace

namespace juce { //… all the code }

Now this could cause a nervous twitch in those devs (myself included) who are used to a more strict “symantec” approach to programming.  Here’s why.

The line “namespace juce” assigns the code within its scope (the curly braces) to the “juce” namespace.  Any code that shares the same namespace automatically has access to the other code within that namespace.  There is no need to tell the compiler that you are using the namespace you are already in.  So what this code is saying is that all the code in the braces belongs to the juce namespace.    Strictly speaking, this is not “using” code from a different namespace.

The question, then, is does the code in the braces actually belong to the “juce” namespace?  Is it part of the JUCE library, in which case this is sementically correct,  or is it something that makes use of the JUCE library in which case, we could think about putting this in it’s own namespace, and start using “Using” or fully qualified namespaces to make use of the JUCE library.

So here’s the thing.  Programming is supposed to be fun, at least that’s why I got into programming.  Josh’s suggestion of adding your code to the “juce” namespace works.  If you’re working by yourself, and you always use this approach, then that could work out just fine for you.  The challenge comes when there are a group of people (or will be a group of people) working on the code, or you this might be  a long term project for you.  For someone else looking at the code (or you coming back to the code after a number of months/years), this might not make sense.

This is where “standards” come in.  Now you don’t have to use the accepted standards.  You could come up with your own and, as long as everybody understands and uses that standard, all should be good.  But if you are expecting to get new people on your team, or need to share the code outside of your “coding circle”, standards make it easier for everybody to be using the same approach and to get on with the task at hand, rather than spend time figuring out what the previous developer has done.

Once again we are back to talking about specificity and clarity of intent. Should you a programmer revisit Josh’s code months or years down the line, is the intent that the code is part of the specific Juce library, or is it specific to another project?

So really, once again, its down to you to make a decision on how you code.  It’s really all down to context, and who you are working with, what your personal or team preferences are, and what the future holds for your project.

A final thought on the benefits of namespacing

Namespacing makes our programming lives easier. For me, one of the biggest benefits comes with naming classes, methods etc. As an example, let’s think about an imaginary but commonly used method in audio programming, creating a sine wave. In a whole host of audio programming libraries, including JUCE, there will be a synthesizer. But what if I wanted to come up with my own specific approach to generating a sine wave, to specific tolerances for the specific purpose of my software?

Looking at the other libraries, there will be such method names as “synth”, “synthesizer”, “mutliSynth” etc etc – the possibilities are endless. With some many useful names taken up, what should I do – although unique, I think “StusFunkySynthomograph” is a bit of a mouthful, hard to read, not obvious, and not really that necessary. By wrapping my synth class code in a namespace, such as stuSynth, I can still use clear and obvious naming such as getSinWave. To make use of this all I’d need to do then is use stuSynth::synth.

The Audio Programmer Logo

Connect with the Audio Programmer community and find out about new tutorials, jobs, and events!

You have Successfully Subscribed!