Idea: the JuceDemoPlugin code read out loud/discussed in a video


#1

Hi all,

I'm getting back into c++ programming for music and audio after quite some years. I'm intruiged by how the JUCE community seems to be the nexus of a new phase in audio software development; very nice. I'm looking forward to finding out I can afford the closed-source license, too :)

As my conversational grasp of c++ is super-rusty (and probably wasn't all that all-encompassing to begin with), and understanding that it'll be a while until the official tutorial for programming a MIDI-to-audio plugin comes out, I was wondering the following:

Would anyone that's set up to do so be willing to simply make a screencast of them reading through the current JuceDemoPlugin code? I think that would make it a lot easier for me & others to already be able to google certain topics using fitting terms, instead of browsing through cplusplus.com for instance to find a certain combination of ampersand and colon and what that means again.

And to get a basic overview of the various structures and functionalities that go into a piece of code like that. I'd be happy to return a similar favour somewhere down the line.

Thanks in advance!

 

 


#2

Thanks for the suggestion! We're certainly interested in getting more educational content out into the world.

In the meantime, we do have some tutorials (http://www.juce.com/learn/tutorials), some of which cover MIDI, others of which cover making audio plugins and so on. Perhaps there's something useful for you there?

 


#3

Thanks yes I'm already delving into those; looking to combine the MIDI example with the JuceDemoPlugin sine generator at the moment to see where I end up.

I've also been immersing myself into the general C++ tutorial over at http://www.cplusplus.com/doc/tutorial/ - quite a challenge still to find there what's meant for instance with this line in the PluginEditor.h of the JuceDemoPlugin:

void paint (Graphics&) override;

Especially the ampersand after the Graphics argument - I'd never seen this before in C++, I gather now that it concerns 'passing an argument by reference' or something of the sort, and that this is a matter of optimisation?

Also the term 'override' isn't mentioned anywhere in that entire tutorial... so I'm guessing in general it might be a good idea if these kinds of code stylings could be addressed in a Juce-specific (re)introduction to C++.


#4

I think that you really just need to read a good C++ book. Tutorials can be very helpful, but you probably won't learn everything you need to know from them. There's nothing like learning from a good book. I like to recommend Programming Principles and Practice using C++ 2nd Ed. by Bjarne Stroustrup, especially for a beginner. There are some other really good C++ books, but I think a beginner can get the most out of that book.

Someone might be able to explain everything about some example code to you and you might understand it, but you probably wouldn't be able to move much further without knowing much about C++ or programming in general. I say this as someone that tried to mess around with JUCE without knowing much of C++. After about 10 chapters of that book, I could at least understand what to do to write something useful.

By the way, a reference is just an alias for some other object. It can be an optimization (usually a const reference), but it can also be used to change the original object that was passed in. That's what I'm guessing it's happening here. It might not do any good to use a copy of the Graphics object. The override keyword doesn't do anything, from what i understand. It's like a "marker" that you can use to say that a function is overridden (probably a virtual function). It does have the useful property that it'll cause a compile error if the member function isn't actually overriding anything. That can help prevent misspellings or something like that.


#5

Right, thanks for that clarification and the book tip, I'll look into it.

Just to be clear on my original video idea: I wasn't thinking about someone explaining every detail about the JuceDemoPlugin code so I could learn c++ from that (I've already mastered it well enough to publish software that's been used worldwide before); I was thinking of someone merely reading a piece of code out loud, so that the typical c++ terms/functionalities become clear, or at least clear enough for someone to be able to google them and learn more about them in that way.

In general I think this type of conversational grasp of code is very handy, like one would learn from a teacher or would use when discussing code with a colleague. 

edit: whoops I should've made this into a reply to your comment, can't see how to remove this post now though


#6

Yeah, good request.

It's tricky for us to do these tutorials, because people have very different levels - many people who already know C++ but want to learn just about the JUCE classes would find it boring and distracting to have the syntax explained.. But others who don't know C++ would find this stuff great learning material. Hard to please everyone!


#7

Ahh I see. I do think that would be a great way to learn. I especially think that learning a language using a framework/library that you might use in real code would really help. It can get a bit dull just making (somewhat) useless console apps, but that can also be quite effective. I think it would be hard to teach language details and also teach the language details, while pleasing everyone. Im not sure if that's the kind of thing the library provider would do though. Perhaps describing why a certain language feature was used could be a good idea though, when it's important.


#8

Alright here's a little experiment:

I documented my efforts this evening in making a very simple sine synth plug, using the Projucer plugin template and code from the 'audio plugin demo' example from the 4.0.1 release I downloaded from Github. Here it is in all its glory; I haven't got it completely working yet but I'm getting there it seems. I'm curious whether it makes any sense to share a coding/debugging session like this, might be a long/tedious read, might also be helpful in terms of conversational-style tutorials. Anyways here goes:

 

create Audio Plugin with Projucer 4.0.2 named ’SineSynth’

set Plugin Channel Configurations to {0, 2}

make sure ‘Plugin is a Synth’ is ticked

make sure ‘Plugin wants midi input’ is ticked

Save project and open in IDE

Build Settings: Deployment: set OS X Deployment Target to OS X 10.10 

(I’m on Xcode 7.1.1 in Yosemite, somehow this defaults to 10.11 as deployment target which makes for non-loading plugins)

Build

Open in Juce Plug-In Host (scan for new or updated plugins)

check build effectiveness by changing Hello World into Hallo World - reopen in Plug-In Host, works

 

load fresh version of ‘audio plugin demo’ from  JUCE-4.0.1.zip into examples folder

open JuceDemoPlugin.jucer in Projucer 4.0.2

save and open in IDE

build settings - deployment target 10.10

build - works

change Troughput level into Throughput Level - build - works.

 

now to copy the sine generator from the JuceDemoPlugin to the newly made SineSynth:

 

compare the PluginProcessor.h files from both open .jucer projects

hmm processBlock() from the JuceDemoPlugin (JDP) is slightly more defined:

void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) override;

versus in SineSynth (SS):

void processBlock (AudioSampleBuffer&, MidiBuffer&) override;

 

JDP has a reset function:

void reset() override;

JDP’s hasEditor’s function is immediately defined:

bool hasEditor() const override                  { return true; }

whereas SS’s isn’t:

bool hasEditor() const override;

 

also JDP:

const String getName() const override            { return JucePlugin_Name; }

SS:

const String getName() const override;

some other differences similar to these, not gonna bother with those now

let’s see if I can copy the sine synth functionality from JDP to SS

 

copy this from the private parts of the class declaration:

 // the synth!

    Synthesiser synth;

 

switch to viewing both PluginProcessor.cpp files side by side and compare

why is there on JDP’s line 14:

AudioProcessor* JUCE_CALLTYPE createPluginFilter();

when SS doesn’t have this? does this call really need to be made here?

assuming for now that it doesn’t

 

copying all the SineWave stuff from JDP line 17 to 179 to the top of SS, after the #include statements

 

now for the constructor, copying lines 198 to 202 from JDP to SS:

// Initialise the synth...

    for (int i = 4; --i >= 0;)

        synth.addVoice (new SineWaveVoice());   // These voices will play our custom sine-wave sounds..


    synth.addSound (new SineWaveSound());

 

now for prepareToPlay(), copy line 214:

synth.setCurrentPlaybackSampleRate (newSampleRate);

to SS’s prepareToPlay() method, changing newSampleRate to sampleRate

 

now for processBlock(): first clear out all the code from SS because we’re dealing with a zero input, two output synth here, 

all the standard code there deals with input audio processing

 

copy from JDP: 

const int numSamples = buffer.getNumSamples();

    synth.renderNextBlock (buffer, midiMessages, 0, numSamples);

 

save and build SS - build succesful

open in Juce Plug-In Host: Couldn’t create filter, This plug-in failed to load correctly

errrmmm

 

maybe add this at the top of SS’s PluginProcessor.cpp then?

AudioProcessor* JUCE_CALLTYPE createPluginFilter();

 

VST again fails to load in plugin host

AU does load but doesn’t output anything

 

let’s set up that debugging toolchain I read about earlier between Xcode and Juce Plug-in Host

follow instructions for that on http://www.juce.com/doc/tutorial_create_projucer_basic_plugin

 

build and run SS from Xcode, which now opens Plug-in Host automatically

within that open SineSynth.vst, again error dialog pops up; 

in all output in Xcode the following is visible:

 

JUCE v4.0.1

Attempting to load VST: /Users/crosswick/Library/Audio/Plug-Ins/VST/SineSynth.vst

2015-11-27 22:17:46.533 Plugin Host[5063:945279] Error loading /Users/crosswick/Library/Audio/Plug-Ins/VST/SineSynth.vst/Contents/MacOS/SineSynth:  dlopen(/Users/crosswick/Library/Audio/Plug-Ins/VST/SineSynth.vst/Contents/MacOS/SineSynth, 262): Library not loaded: /System/Library/Frameworks/CoreImage.framework/Versions/A/CoreImage

  Referenced from: /Users/crosswick/Library/Audio/Plug-Ins/VST/SineSynth.vst/Contents/MacOS/SineSynth

  Reason: image not found

CoreImage, excuse me? what the

why did it compile and run before? did I change anything graphics wise, or should I?

let’s do a Project - Clean in Xcode and check again

wait is this the deployment target stuff again?

argh seems so (but also yay) - how would one specify this build setting in Projucer…

 

right SS runs now but with some kind of crazy fast delay feedback happening

would this be down to that piece of code again? let’s remove that again at the top:

AudioProcessor* JUCE_CALLTYPE createPluginFilter();

 

nope, still the same. now let’s check it in concordance with the JDP in action

with JDP as MIDI insert between MIDI input and SineSynth, the weird delay/feedback from SS is gone?!

how is this possible? aren’t JDP and SS supposed to be in their own separate memory spaces?

perhaps there’s some explicitly hacky code in the SineWaveSound code I copied?

lemme read through that code and see if anything sticks out

 

you know what, let’s empty the audio buffer at first in SS’s processBlock() just to be sure. 

it’s not done in JDP of course seen as that’s also an effect with audio input

oops deleted the code that did that already, let’s make another dummy plugin to get it back and paste it

it was

 for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i)

        buffer.clear (i, 0, buffer.getNumSamples());

aight save all, build in Xcode

 

yes! now we’ve got normal sines sounding; note off doesn’t work though, let’s investigate

JDP doesn’t show the same behavior within the same host & MIDI setup

perhaps JDP’s reset() method? nah that only deals with the delay thing which I’m not copying in SS 

how does a note off message get processed in JDP?

 

wait let’s delete the FloatParameter stuff, I don’t think I need that, that might be interfering

nope still the same, but good riddance anyway I guess

 

any other methods I should copy from JDP to SS? in the Editor even perhaps?

wait, perhaps the MidiKeyboardState stuff (which I haven’t copied to SS yet) is somehow responsible for properly managing MIDI info?

let’s copy that stuff in starting with 

// this is kept up to date with the midi messages that arrive, and the UI component

    // registers with it so it can represent the incoming messages

MidiKeyboardState keyboardState;

in PluginProcessor.h

 

and the following to SS’s processBlock() right before the synth.renderBlock call:

// Now pass any incoming midi messages to our keyboard state object, and let it

    // add messages to the buffer if the user is clicking on the on-screen keys

    keyboardState.processNextMidiBuffer (midiMessages, 0, numSamples, true);

I wonder whether this is enough or I should actually add the corresponding GUi object too… let’s see if this builds

it does build and run, still no note off though…

well then… errrrm


#9

Right exactly! It appears to me that such an introduction to typical code examples might be something that's very welcome in modern c++ programming, comparable to the awesome strides that are being made with the Projucer in terms of rapidly evaluating (small) changes to GUI design and other stuff.


#10

Well I'll spare you guys today's long list of brave attempts to get this working :) for a loooong time I was working from the assumption that 

keyboardState.processNextMidiBuffer (midiMessages, 0, numSamples, true);​

was somehow needed for proper MIDI note handling, so I spent a lot of time implementing that whole deal with the MidiKeyboard GUI object, which was a good learning experience in itself, note offs still wouldn't happen though...

In the end I noticed that my JuceDemoPlugin was displaying the same behavior, even with the above line intact (I had commented it out, compiled it and had gotten erratic note-off behavior, hence my hypothesis), so I compiled a fresh JDP from the Github .zip which did work;

After comparing the source files from these two JDP versions with the FileMerge app I saw that an essential value in the note-off mechanism had been changed somehow: 

if (tailOff == -0.703168) // we only need to begin a tail-off if it's not already doing so - the
                                // stopNote method could be called more than once.

that value is supposed to be 0.0 - I guess I accidentally hit it with the mouse before copying over the SineWaveVoice over to my SineSynth project, altering it with the slider that pops up in Projucer as part of the (otherwise awesome) live coding situation.

That took a while :) very glad to have it working now, looking forward to the next steps of including my own synth code.


#11

Yeah I can imagine... still it might be interesting to test this new approach out; perhaps for the upcoming tutorial on building a MIDI-to-Audio plugin, it might be nice if you could record a video of you reading the code out loud (while pointing at portions of it with the mouse) like you would to yourself - so not necessarily geared towards any type of external audience.

I'd be happy to type out subtitles for that, so people of any C++ level can at least google all the spoken terms with accuracy. Also I tend to believe that there would be a lot of extra useful information in how you would intonate the description of various bits of code; to get a sense of their relative importance.

Thanks for JUCE in general BTW!