Getting off the ground


#1

I need to build a very simple cross-platform audio plugin (supporting AU on Mac, and VST on Windows). I found the Juce system and it looks like it might be perfect (and if it works, I will need to buy it as I will be building a commerical product with it). However, I’m having initial teething problems with it as I have been unable to find any high-level documentation (I regret that I’m not a fan of doxygen/javadocs style documentation, I’m not a bottom-up type developer :oops: )

So I pulled everything down and built the audio plugin demo and then discovered it was showing up as an effect rather than an instrument. It’s not at all clear to me how to change it and although I am sure I could figure it out if I spent a LONG time with the code, I really don’t want to become an expert in this stuff, just need enough to do what I need.

I also found the new standalone component builder, which is a WONDERFUL addition but again it is not clear to me how I produce something that can be the GUI for the audio plugin ---- a tutorial for that would be tremendously helpful.

Thanks,
David


#2

Sorry, there aren’t a lot of top-down docs for this stuff!

The easiest way to do a plugin is to run the new (experimental) jucer and select “new project”. If your project is a plugin, it lets you edit all the settings, so you can set stuff like the effect/instrument type there.

The GUI for an audio plugin is just a normal component, there’s no special case for it. If you’ve created a component with the jucer, you’d just stick it inside your AudioProcessorEditor like you would any other component.


#3

Juce uses some flags to set different values.
For audio plugins there’s a file called JucePluginCharacteristics.h.
You can find it in the pluginFolder/JuceLibraryCode folder.
This file is located in that specific folder because all demo projects of juce are generated using the Jucer(experimental).
I suggest to build the jucer and try it.
When you create a new project with the jucer you can choose what kind of project to build (standalone application, audio plugin…)
and then you can turn on/off all the flags from it.
Hope this helps =)

EDIT: oh, Julian, you are always the fastest…


#4

Thanks for the quick responses — I had in fact found those other pieces (jucer, the experimental Jucer, etc) and understood them individually but the real issue was how they all integrate without a lot of manual work.

I wonder if someone could expand the statement “you’d just stick it inside your AudioProcessorEditor like you would any other component.”

For example, I can use “The Jucer V3.0.0” to create those four source files “Plugin*.*” and an xCode project. I can then use the “other” Jucer (why do these two different things have the same name) to create a component with a button in it (say) and I can see that it produces some source code files. But where in that already xcode project do you setup the references to the new code with the component and button so that it will be opened when you edit the plugin?

I apologize if these questions seem naive but I’m trying to put something together really quickly to determine whether it’s worth the effort and I don’t really want to put a huge effort into learning Juce until I can evaluate whether it will help me.

Thanks,
D


#5

The new jucer is a work-in-progress - eventually it’ll do everything, and will replace the old one, but I’ve not finished it yet…


#6

I understand that — and, by the way, I think it’s a terrific environment. I particularly like your code style with the * “attached” to the type rather than the variable…you must have Pascal in your background :slight_smile: Far more readable than the way a lot of people write C & C++

FWIW, I typically go one step further and typedef those kinds of things so I don’t have to use the * in parameter argument lists at all.

(I’d still love it if someone could expand that statement about the AudioProcessorEditor :wink: )


#7

OK — let me try to ask a more specific question.

I can see that if I use the Experimental Jucer, I can create a project that will be an AudioPlugin. And I can see that there is also a class defined (MyFirstAudioProcessorEditor, say), an instance of which presumably gets created when one tries to edit a plugin from a DAW.

I can also see that I can create a Jucer “component” (called MyJucerComponent, say) which is using multiple inheritance to pull in some abstract classes that need to be implemented to respond to events.

So I think my only question is, how is MyJucerComponent supposed to be attached to MyFirstAudioProcessorEditor? Am I supposed to create one dynamically on the fly inside the MyFirstAudioProcessorEditor constructor and everything will just work? If that’s the case, what am I supposed to do with that ::paint member function?


#8

From looking at the example JuceDemoPlugin code, it looks like one actually has to mostly MERGE the code created by the component editor into the created PluginEditor h and cpp files, and not actually using the component editor code at all.

This seems like it will get awkard because that merge will have to be done everytime you use the component editor to modify the GUI piece.

Am I missing something?


#9

Well, doing the merge seems to work…I was able to get an audio unit into my DAW with some GUI stuff…very nice…

Hopefully my comment chain will help the next newbie get up to speed quickly.


#10

I don’t really understand what you mean about “merging”… If you use the old jucer to create a component cpp and h, just add those files to your project, then in your plugin editor comp, add an instance of your new component as a child comp… No need to cut-and-paste anything.


#11

In the absense of documentation, I finally took a look at the code for the JuceDemoPlugin.

I noted that the main class defined in PluginEditor.h file, called JuceDemoPluginAudioProcessorEditir, inherited both from AudioProcessorEditor AND from two classes (SliderListener and Timer). That class also defined some private instance variables for things like a Label, a Slider or two and so on.

Since the Experimental Jucer generated a skeleton for the Audio Unit plugin, and the other Jucer created those GUI component.h/cpp files to which you referred (and which contained things like the SliderListener and the private variables for Labels, Sliders), the only way I could see to get something that was structured the same way as your JuceDemoPlugin example was to merge most of the code in component.h/cpp into PluginEditor.h/cpp

In a previous post, I asked if one was supposed to create an instance of the component inside the pluginEditor (and how then to invoke it) but nobody responded so I gave in and started looking at the example code which let me to the solution above.

I’d love to see code that shows a way to do it without having to combine them, it was certainly awkard to do it.


#12

Search for “addAndMakeVisible” or “addChildComponent” for about a million examples of how to add one component to another one!


#13

If that’s how one is supposed to do it, why doesn’t the audio plugin demo which, in the absence of documentation serves as a guideline, do it that way?

Seriously, I love what you’ve done, and we’ll most likely end up with a commercial license for it, but is it really the expectation that we are supposed to figure out the right way to do things both without docs and by NOT using the provided examples? That seems hard


#14

There’s no way that you’re “supposed” to do it - the GUI is just a component like any other, you could construct it in an infinite number of different ways. The demo is hand-coded, so is written as minimally as possible.

Wish I had more time to spend writing docs and helping beginners on the forum, but I’ve got a lot of code that needs writing!


#15

The demo code files indicate in the first line that they are auto-generated by the Jucer

Understood and respected, but I infer from this that you are not interested in having paid customers…I will look for something else.


#16

The demo files were indeed generated by the jucer, but the component inside it was written by me.

That’s a bit of a strange leap of logic - I like paying customers very much! That’s why I like to spend as much time as possible improving the product for them!


#17

Well, I’m originally from Ireland, what can I say! :mrgreen:

Creating good documentation makes a significant contribution to “improving the product”, and often is the most significant piece. Great code is useless if it’s too hard (i.e. takes too long to figure out how) to use it.

Seriously, though, let me explain from where I’m coming.

As a software developer with over 35 years experience (and as a manager of software teams over much of that time), I’ve long understood the tradeoff between time and money. Let’s say the hourly rate for a great developer is $200 and assume there are deadlines with deliverables. If I can buy a tool such that the time to become productive with it is less than the number of hours I would have to spend doing it myself (including learning it), then it’s a no brainer to buy the tool. I’ll save money as well as the ability to get other stuff done. This is even more critical if I need to do something where learning it deeply is an unnecessary distraction from the task at hand. For example, I don’t really care how AUs or VSTs actually work, nor do I want to have to learn yet another GUI framework…I simply want to leverage what you’ve done to get my job done as painlessly as possible and it SEEMS that your libraries can make that possible, with a little bit of guidance.

I have found in practice that high quality support is often worth far more than feature-complete libraries. If there had been an easily found document/tutorial that showed me exactly how to do basic stuff such as creating a cross-platform AU/VST with my own GUI in 10 or 15 minutes using the tools that you have in your library, I would have bought commercial licenses for my team without a second thought.

But I ended up futzing with stuff much of the day (and evening) yesterday and still apparently ended up with the wrong approach.
Those member functions you mentioned that I should have searched for (BTW how is one supposed to know their names up front without a lot of studying first) look like they are adding GUI widgets (components) manually at run time. But you have a GUI component tool that looks like it can create the whole dialog in one go, which is very nice in principle, but useless if it’s not clear how to then “embed” that dialog into the PluginEditor.

It seems to me that a trivial document (or even a movie capture tool) could have been created in a couple of hours to get new users up to speed quickly. THEN you will capture those peoples’ interest as they will be able to determine instantly that the product is worth the effort (and up front cost) even if they haven’t tried it yet, and that’s how one gets paying customers…(at least that’s how I’ve gotten them in the companies I’ve created in the past).

Take care,
D


#18

By the way, The Jucer V3.0.0 default configuration has an item in it that causes AUs to fail validation.


#19

I totally understand, and would love to be able to offer better starter guides + examples. Maybe one day I’ll have a team of technical writers to set to work on things like this…

AFAICT the only failure is that the manufacturer ID doesn’t have an upper-case character - every user would need to set that value anyway, so not a biggie, but thanks, I’ll tweak the default value to avoid any confusion.


#20

OK — perhaps just a teeny hint? Below is the scaffolding in a PluginEditor.
There is separately defined a GUI component with a few controls in it…the class is called AUEditorComponent, created with your Jucer app

What exactly do I need to put in the constructor, destructor, and paint member functions of the AudioProcessorEditor to make this GUI component be displayed?

Thanks,
D

//==============================================================================
ScorecererPluginAudioProcessorEditor::ScorecererPluginAudioProcessorEditor (ScorecererPluginAudioProcessor* ownerFilter)
: AudioProcessorEditor (ownerFilter)
{
// This is where our plugin’s editor size is set.
setSize (400, 300);

   /*AUEditorComponent* */  contentComponent = new AUEditorComponent();  //  variable is declared as part of the class
   addChildComponent(contentComponent);
   // ???? how do I make it visible.....   the setVisible member function didn't work

}

ScorecererPluginAudioProcessorEditor::~ScorecererPluginAudioProcessorEditor()
{
delete contentComponent; // Is this necessary or is the component automatically deleted because of “addChildComponent”, i.e, owner is responsible?
}

//==============================================================================
void ScorecererPluginAudioProcessorEditor::paint (Graphics& g)
{
// What goes in here, certainly not the following default stuff?

//g.fillAll (Colours::white);
//g.setColour (Colours::black);
//g.setFont (15.0f);
//g.drawFittedText ("Hello World!",
//                  0, 0, getWidth(), getHeight(),
//                  Justification::centred, 1);

}