void Project::setMissingAudioPluginDefaultValues()
{
    const String sanitisedProjectName (CodeHelpers::makeValidIdentifier (getTitle(), false, true, false));

    setValueIfVoid (shouldBuildVST(),                   true);
    setValueIfVoid (shouldBuildVST3(),                  false);
    setValueIfVoid (shouldBuildAU(),                    true);
    setValueIfVoid (shouldBuildAUv3(),                  false);
    setValueIfVoid (shouldBuildRTAS(),                  false);
    setValueIfVoid (shouldBuildAAX(),                   false);
    setValueIfVoid (shouldBuildStandalone(),            false);

    setValueIfVoid (getPluginName(),                    getTitle());
    setValueIfVoid (getPluginDesc(),                    getTitle());
    setValueIfVoid (getPluginManufacturer(),            "yourcompany");
    setValueIfVoid (getPluginManufacturerCode(),        "Manu");
    setValueIfVoid (getPluginCode(),                    makeValid4CC (getProjectUID() + getProjectUID()));
    setValueIfVoid (getPluginChannelConfigs(),          String());
    setValueIfVoid (getPluginIsSynth(),                 false);
    setValueIfVoid (getPluginWantsMidiInput(),          false);
    setValueIfVoid (getPluginProducesMidiOut(),         false);
    setValueIfVoid (getPluginIsMidiEffectPlugin(),      false);
    setValueIfVoid (getPluginEditorNeedsKeyFocus(),     false);
    setValueIfVoid (getPluginAUExportPrefix(),          sanitisedProjectName + "AU");
    setValueIfVoid (getPluginRTASCategory(),            String());
    setValueIfVoid (getBundleIdentifier(),              getDefaultBundleIdentifier());
    setValueIfVoid (getAAXIdentifier(),                 getDefaultAAXIdentifier());
    setValueIfVoid (getPluginAAXCategory(),             "AAX_ePlugInCategory_Dynamics");
}
Example #2
0
    void setMissingProjectProperties (Project& project) const
    {
        const String sanitisedProjectName (CodeHelpers::makeValidIdentifier (project.getTitle(), false, true, false));

        setValueIfVoid (shouldBuildVST (project), true);
        setValueIfVoid (shouldBuildVST3 (project), false);
        setValueIfVoid (shouldBuildAU (project),  true);
        setValueIfVoid (shouldBuildRTAS (project), false);
        setValueIfVoid (shouldBuildAAX (project), false);

        setValueIfVoid (getPluginName (project),                   project.getTitle());
        setValueIfVoid (getPluginDesc (project),                   project.getTitle());
        setValueIfVoid (getPluginManufacturer (project),           "yourcompany");
        setValueIfVoid (getPluginManufacturerCode (project),       "Manu");
        setValueIfVoid (getPluginCode (project),                   makeValid4CC (project.getProjectUID() + project.getProjectUID()));
        setValueIfVoid (getPluginChannelConfigs (project),         "");
        setValueIfVoid (getPluginIsSynth (project),                false);
        setValueIfVoid (getPluginWantsMidiInput (project),         false);
        setValueIfVoid (getPluginProducesMidiOut (project),        false);
        setValueIfVoid (getPluginIsMidiEffectPlugin (project),     false);
        setValueIfVoid (getPluginEditorNeedsKeyFocus (project),    false);
        setValueIfVoid (getPluginAUExportPrefix (project),         sanitisedProjectName + "AU");
        setValueIfVoid (getPluginRTASCategory (project),           String::empty);
        setValueIfVoid (project.getBundleIdentifier(),             project.getDefaultBundleIdentifier());
        setValueIfVoid (project.getAAXIdentifier(),                project.getDefaultAAXIdentifier());
        setValueIfVoid (getPluginAAXCategory (project),            "AAX_ePlugInCategory_Dynamics");
    }
Example #3
0
    void setMissingProjectProperties (Project& project) const
    {
        const String sanitisedProjectName (CodeHelpers::makeValidIdentifier (project.getTitle(), false, true, false));

        setValueIfVoid (shouldBuildVST (project), true);
        setValueIfVoid (shouldBuildAU (project),  true);

        setValueIfVoid (getPluginName (project),                   project.getTitle());
        setValueIfVoid (getPluginDesc (project),                   project.getTitle());
        setValueIfVoid (getPluginManufacturer (project),           "yourcompany");
        setValueIfVoid (getPluginManufacturerCode (project),       "Manu");
        setValueIfVoid (getPluginCode (project),                   "Plug");
        setValueIfVoid (getPluginChannelConfigs (project),         "{1, 1}, {2, 2}");
        setValueIfVoid (getPluginIsSynth (project),                false);
        setValueIfVoid (getPluginWantsMidiInput (project),         false);
        setValueIfVoid (getPluginProducesMidiOut (project),        false);
        setValueIfVoid (getPluginSilenceInProducesSilenceOut (project), false);
        setValueIfVoid (getPluginTailLengthSeconds (project),      0);
        setValueIfVoid (getPluginEditorNeedsKeyFocus (project),    false);
        setValueIfVoid (getPluginAUExportPrefix (project),         sanitisedProjectName + "AU");
        setValueIfVoid (getPluginAUCocoaViewClassName (project),   sanitisedProjectName + "AU_V1");
        setValueIfVoid (getPluginRTASCategory (project),           String::empty);
        setValueIfVoid (project.getBundleIdentifier(),             project.getDefaultBundleIdentifier());
        setValueIfVoid (project.getAAXIdentifier(),                project.getDefaultAAXIdentifier());
        setValueIfVoid (getPluginAAXCategory (project),            "AAX_ePlugInCategory_Dynamics");
    }
Example #4
0
    void createPropertyEditors (Project& project, PropertyListBuilder& props) const
    {
        props.add (new BooleanPropertyComponent (shouldBuildVST (project), "Build VST", "Enabled"),
                   "Whether the project should produce a VST plugin.");
        props.add (new BooleanPropertyComponent (shouldBuildAU (project), "Build AudioUnit", "Enabled"),
                   "Whether the project should produce an AudioUnit plugin.");
        props.add (new BooleanPropertyComponent (shouldBuildRTAS (project), "Build RTAS", "Enabled"),
                   "Whether the project should produce an RTAS plugin.");
        props.add (new BooleanPropertyComponent (shouldBuildAAX (project), "Build AAX", "Enabled"),
                   "Whether the project should produce an AAX plugin.");

        props.add (new TextPropertyComponent (getPluginName (project), "Plugin Name", 128, false),
                   "The name of your plugin (keep it short!)");
        props.add (new TextPropertyComponent (getPluginDesc (project), "Plugin Description", 256, false),
                   "A short description of your plugin.");

        props.add (new TextPropertyComponent (getPluginManufacturer (project), "Plugin Manufacturer", 256, false),
                   "The name of your company (cannot be blank).");
        props.add (new TextPropertyComponent (getPluginManufacturerCode (project), "Plugin Manufacturer Code", 4, false),
                   "A four-character unique ID for your company. Note that for AU compatibility, this must contain at least one upper-case letter!");
        props.add (new TextPropertyComponent (getPluginCode (project), "Plugin Code", 4, false),
                   "A four-character unique ID for your plugin. Note that for AU compatibility, this must contain at least one upper-case letter!");

        props.add (new TextPropertyComponent (getPluginChannelConfigs (project), "Plugin Channel Configurations", 256, false),
                   "This is the set of input/output channel configurations that your plugin can handle.  The list is a comma-separated set of pairs of values in the form { numInputs, numOutputs }, and each "
                   "pair indicates a valid configuration that the plugin can handle. So for example, {1, 1}, {2, 2} means that the plugin can be used in just two configurations: either with 1 input "
                   "and 1 output, or with 2 inputs and 2 outputs.");

        props.add (new BooleanPropertyComponent (getPluginIsSynth (project), "Plugin is a Synth", "Is a Synth"),
                   "Enable this if you want your plugin to be treated as a synth or generator. It doesn't make much difference to the plugin itself, but some hosts treat synths differently to other plugins.");

        props.add (new BooleanPropertyComponent (getPluginWantsMidiInput (project), "Plugin Midi Input", "Plugin wants midi input"),
                   "Enable this if you want your plugin to accept midi messages.");

        props.add (new BooleanPropertyComponent (getPluginProducesMidiOut (project), "Plugin Midi Output", "Plugin produces midi output"),
                   "Enable this if your plugin is going to produce midi messages.");

        props.add (new BooleanPropertyComponent (getPluginSilenceInProducesSilenceOut (project), "Silence", "Silence in produces silence out"),
                   "Enable this if your plugin has no tail - i.e. if passing a silent buffer to it will always result in a silent buffer being produced.");

        props.add (new BooleanPropertyComponent (getPluginEditorNeedsKeyFocus (project), "Key Focus", "Plugin editor requires keyboard focus"),
                   "Enable this if your plugin needs keyboard input - some hosts can be a bit funny about keyboard focus..");

        props.add (new TextPropertyComponent (getPluginAUExportPrefix (project), "Plugin AU Export Prefix", 64, false),
                   "A prefix for the names of exported entry-point functions that the component exposes - typically this will be a version of your plugin's name that can be used as part of a C++ token.");

        props.add (new TextPropertyComponent (getPluginAUMainType (project), "Plugin AU Main Type", 128, false),
                   "In an AU, this is the value that is set as JucePlugin_AUMainType. Leave it blank unless you want to use a custom value.");

        props.add (new TextPropertyComponent (getPluginRTASCategory (project), "Plugin RTAS Category", 64, false),
                   "(Leave this blank if your plugin is a synth). This is one of the RTAS categories from FicPluginEnums.h, such as: ePlugInCategory_None, ePlugInCategory_EQ, ePlugInCategory_Dynamics, "
                   "ePlugInCategory_PitchShift, ePlugInCategory_Reverb, ePlugInCategory_Delay, "
                   "ePlugInCategory_Modulation, ePlugInCategory_Harmonic, ePlugInCategory_NoiseReduction, "
                   "ePlugInCategory_Dither, ePlugInCategory_SoundField");

        props.add (new TextPropertyComponent (getPluginAAXCategory (project), "Plugin AAX Category", 64, false),
                   "This is one of the RTAS categories from the AAX_EPlugInCategory enum");
    }
void Project::createAudioPluginPropertyEditors (PropertyListBuilder& props)
{
    props.add (new BooleanPropertyComponent (shouldBuildVST(), "Build VST", "Enabled"),
               "Whether the project should produce a VST plugin.");
    props.add (new BooleanPropertyComponent (shouldBuildVST3(), "Build VST3", "Enabled"),
               "Whether the project should produce a VST3 plugin.");
    props.add (new BooleanPropertyComponent (shouldBuildAU(), "Build AudioUnit", "Enabled"),
               "Whether the project should produce an AudioUnit plugin.");
    props.add (new BooleanPropertyComponent (shouldBuildAUv3(), "Build AudioUnit v3", "Enabled"),
               "Whether the project should produce an AudioUnit version 3 plugin.");
    props.add (new BooleanPropertyComponent (shouldBuildRTAS(), "Build RTAS", "Enabled"),
               "Whether the project should produce an RTAS plugin.");
    props.add (new BooleanPropertyComponent (shouldBuildAAX(), "Build AAX", "Enabled"),
               "Whether the project should produce an AAX plugin.");

    /* TODO: this property editor is temporarily disabled because right now we build standalone if and only if
       we also build AUv3. However as soon as targets are supported on non-Xcode exporters as well, we should
       re-enable this option and allow to build the standalone plug-in independently from AUv3.
    */
    // props.add (new BooleanPropertyComponent (shouldBuildStandalone(), "Build Standalone", "Enabled"),
    //            "Whether the project should produce a standalone version of the plugin. Required for AUv3.");

    props.add (new TextPropertyComponent (getPluginName(), "Plugin Name", 128, false),
               "The name of your plugin (keep it short!)");
    props.add (new TextPropertyComponent (getPluginDesc(), "Plugin Description", 256, false),
               "A short description of your plugin.");

    props.add (new TextPropertyComponent (getPluginManufacturer(), "Plugin Manufacturer", 256, false),
               "The name of your company (cannot be blank).");
    props.add (new TextPropertyComponent (getPluginManufacturerCode(), "Plugin Manufacturer Code", 4, false),
               "A four-character unique ID for your company. Note that for AU compatibility, this must contain at least one upper-case letter!");
    props.add (new TextPropertyComponent (getPluginCode(), "Plugin Code", 4, false),
               "A four-character unique ID for your plugin. Note that for AU compatibility, this must contain at least one upper-case letter!");

    props.add (new TextPropertyComponent (getPluginChannelConfigs(), "Plugin Channel Configurations", 1024, false),
               "This list is a comma-separated set list in the form {numIns, numOuts} and each pair indicates a valid plug-in "
               "configuration. For example {1, 1}, {2, 2} means that the plugin can be used either with 1 input and 1 output, "
               "or with 2 inputs and 2 outputs. If your plug-in requires side-chains, aux output buses etc., then you must leave "
               "this field empty and override the setPreferredBusArrangement method in your AudioProcessor.");

    props.add (new BooleanPropertyComponent (getPluginIsSynth(), "Plugin is a Synth", "Is a Synth"),
               "Enable this if you want your plugin to be treated as a synth or generator. It doesn't make much difference to the plugin itself, but some hosts treat synths differently to other plugins.");

    props.add (new BooleanPropertyComponent (getPluginWantsMidiInput(), "Plugin Midi Input", "Plugin wants midi input"),
               "Enable this if you want your plugin to accept midi messages.");

    props.add (new BooleanPropertyComponent (getPluginProducesMidiOut(), "Plugin Midi Output", "Plugin produces midi output"),
               "Enable this if your plugin is going to produce midi messages.");

    props.add (new BooleanPropertyComponent (getPluginIsMidiEffectPlugin(), "Midi Effect Plugin", "Plugin is a midi effect plugin"),
               "Enable this if your plugin only processes midi and no audio.");

    props.add (new BooleanPropertyComponent (getPluginEditorNeedsKeyFocus(), "Key Focus", "Plugin editor requires keyboard focus"),
               "Enable this if your plugin needs keyboard input - some hosts can be a bit funny about keyboard focus..");

    props.add (new TextPropertyComponent (getPluginAUExportPrefix(), "Plugin AU Export Prefix", 64, false),
               "A prefix for the names of exported entry-point functions that the component exposes - typically this will be a version of your plugin's name that can be used as part of a C++ token.");

    props.add (new TextPropertyComponent (getPluginAUMainType(), "Plugin AU Main Type", 128, false),
               "In an AU, this is the value that is set as JucePlugin_AUMainType. Leave it blank unless you want to use a custom value.");

    props.add (new TextPropertyComponent (getPluginVSTCategory(), "VST Category", 64, false),
               "In a VST, this is the value that is set as JucePlugin_VSTCategory. Leave it blank unless you want to use a custom value.");

    props.add (new TextPropertyComponent (getPluginRTASCategory(), "Plugin RTAS Category", 64, false),
               "(Leave this blank if your plugin is a synth). This is one of the RTAS categories from FicPluginEnums.h, such as: ePlugInCategory_None, ePlugInCategory_EQ, ePlugInCategory_Dynamics, "
               "ePlugInCategory_PitchShift, ePlugInCategory_Reverb, ePlugInCategory_Delay, "
               "ePlugInCategory_Modulation, ePlugInCategory_Harmonic, ePlugInCategory_NoiseReduction, "
               "ePlugInCategory_Dither, ePlugInCategory_SoundField");

    props.add (new TextPropertyComponent (getPluginAAXCategory(), "Plugin AAX Category", 64, false),
               "This is one of the categories from the AAX_EPlugInCategory enum");

    props.add (new TextPropertyComponent (getAAXIdentifier(), "Plugin AAX Identifier", 256, false),
               "The value to use for the JucePlugin_AAXIdentifier setting");
}
Example #6
0
void Project::setMissingDefaultValues()
{
    if (! projectRoot.hasProperty (Ids::id_))
        projectRoot.setProperty (Ids::id_, createAlphaNumericUID(), 0);

    // Create main file group if missing
    if (! projectRoot.getChildWithName (Tags::projectMainGroup).isValid())
    {
        Item mainGroup (*this, ValueTree (Tags::projectMainGroup));
        projectRoot.addChild (mainGroup.getNode(), 0, 0);
    }

    getMainGroup().initialiseNodeValues();

    if (getDocumentTitle().isEmpty())
        setTitle ("Juce Project");

    if (! projectRoot.hasProperty (Ids::projectType))
        getProjectType() = application;

    if (! projectRoot.hasProperty (Ids::version))
        getVersion() = "1.0.0";

    if (! projectRoot.hasProperty (Ids::juceLinkage))
        getJuceLinkageModeValue() = useAmalgamatedJuceViaMultipleTemplates;

    const String juceFolderPath (getRelativePathForFile (StoredSettings::getInstance()->getLastKnownJuceFolder()));

    // Create configs group
    if (! projectRoot.getChildWithName (Tags::configurations).isValid())
    {
        projectRoot.addChild (ValueTree (Tags::configurations), 0, 0);
        createDefaultConfigs();
    }

    if (! projectRoot.getChildWithName (Tags::exporters).isValid())
        createDefaultExporters();

    const String sanitisedProjectName (CodeHelpers::makeValidIdentifier (getProjectName().toString(), false, true, false));

    if (! projectRoot.hasProperty (Ids::buildVST))
    {
        shouldBuildVST() = true;
        shouldBuildRTAS() = false;
        shouldBuildAU() = true;

        getPluginName() = getProjectName().toString();
        getPluginDesc() = getProjectName().toString();
        getPluginManufacturer() = "yourcompany";
        getPluginManufacturerCode() = "Manu";
        getPluginCode() = "Plug";
        getPluginChannelConfigs() = "{1, 1}, {2, 2}";
        getPluginIsSynth() = false;
        getPluginWantsMidiInput() = false;
        getPluginProducesMidiOut() = false;
        getPluginSilenceInProducesSilenceOut() = false;
        getPluginTailLengthSeconds() = 0;
        getPluginEditorNeedsKeyFocus() = false;
        getPluginAUExportPrefix() = sanitisedProjectName + "AU";
        getPluginAUCocoaViewClassName() = sanitisedProjectName + "AU_V1";
        getPluginRTASCategory() = String::empty;
    }

    if (! projectRoot.hasProperty (Ids::bundleIdentifier))
        setBundleIdentifierToDefault();
}
Example #7
0
//==============================================================================
void Project::createPropertyEditors (Array <PropertyComponent*>& props)
{
    props.add (new TextPropertyComponent (getProjectName(), "Project Name", 256, false));
    props.getLast()->setTooltip ("The name of the project.");

    props.add (new TextPropertyComponent (getVersion(), "Project Version", 16, false));
    props.getLast()->setTooltip ("The project's version number, This should be in the format major.minor.point");

    const char* projectTypes[] = { "Application (GUI)", "Application (Non-GUI)", "Audio Plug-in", "Static Library", 0 };
    const char* projectTypeValues[] = { application, commandLineApp, audioPlugin, library, 0 };
    props.add (new ChoicePropertyComponent (getProjectType(), "Project Type", StringArray (projectTypes), Array<var> (projectTypeValues)));

    const char* linkageTypes[] = { "Not linked to Juce", "Linked to Juce Static Library", "Include Juce Amalgamated Files", "Include Juce Source Code Directly (In a single file)", "Include Juce Source Code Directly (Split across several files)", 0 };
    const char* linkageTypeValues[] = { notLinkedToJuce, useLinkedJuce, useAmalgamatedJuce, useAmalgamatedJuceViaSingleTemplate, useAmalgamatedJuceViaMultipleTemplates, 0 };
    props.add (new ChoicePropertyComponent (getJuceLinkageModeValue(), "Juce Linkage Method", StringArray (linkageTypes), Array<var> (linkageTypeValues)));
    props.getLast()->setTooltip ("The method by which your project will be linked to Juce.");

    props.add (new TextPropertyComponent (getBundleIdentifier(), "Bundle Identifier", 256, false));
    props.getLast()->setTooltip ("A unique identifier for this product, mainly for use in Mac builds. It should be something like 'com.yourcompanyname.yourproductname'");

    {
        OwnedArray<Project::Item> images;
        findAllImageItems (images);

        StringArray choices;
        Array<var> ids;

        choices.add ("<None>");
        ids.add (var::null);
        choices.add (String::empty);
        ids.add (var::null);

        for (int i = 0; i < images.size(); ++i)
        {
            choices.add (images.getUnchecked(i)->getName().toString());
            ids.add (images.getUnchecked(i)->getID());
        }

        props.add (new ChoicePropertyComponent (getSmallIconImageItemID(), "Icon (small)", choices, ids));
        props.getLast()->setTooltip ("Sets an icon to use for the executable.");

        props.add (new ChoicePropertyComponent (getBigIconImageItemID(), "Icon (large)", choices, ids));
        props.getLast()->setTooltip ("Sets an icon to use for the executable.");
    }

    if (isAudioPlugin())
    {
        props.add (new BooleanPropertyComponent (shouldBuildVST(), "Build VST", "Enabled"));
        props.getLast()->setTooltip ("Whether the project should produce a VST plugin.");
        props.add (new BooleanPropertyComponent (shouldBuildAU(), "Build AudioUnit", "Enabled"));
        props.getLast()->setTooltip ("Whether the project should produce an AudioUnit plugin.");
        props.add (new BooleanPropertyComponent (shouldBuildRTAS(), "Build RTAS", "Enabled"));
        props.getLast()->setTooltip ("Whether the project should produce an RTAS plugin.");
    }

    if (isAudioPlugin())
    {
        props.add (new TextPropertyComponent (getPluginName(), "Plugin Name", 128, false));
        props.getLast()->setTooltip ("The name of your plugin (keep it short!)");
        props.add (new TextPropertyComponent (getPluginDesc(), "Plugin Description", 256, false));
        props.getLast()->setTooltip ("A short description of your plugin.");

        props.add (new TextPropertyComponent (getPluginManufacturer(), "Plugin Manufacturer", 256, false));
        props.getLast()->setTooltip ("The name of your company (cannot be blank).");
        props.add (new TextPropertyComponent (getPluginManufacturerCode(), "Plugin Manufacturer Code", 4, false));
        props.getLast()->setTooltip ("A four-character unique ID for your company. Note that for AU compatibility, this must contain at least one upper-case letter!");
        props.add (new TextPropertyComponent (getPluginCode(), "Plugin Code", 4, false));
        props.getLast()->setTooltip ("A four-character unique ID for your plugin. Note that for AU compatibility, this must contain at least one upper-case letter!");

        props.add (new TextPropertyComponent (getPluginChannelConfigs(), "Plugin Channel Configurations", 256, false));
        props.getLast()->setTooltip ("This is the set of input/output channel configurations that your plugin can handle.  The list is a comma-separated set of pairs of values in the form { numInputs, numOutputs }, and each "
                                     "pair indicates a valid configuration that the plugin can handle. So for example, {1, 1}, {2, 2} means that the plugin can be used in just two configurations: either with 1 input "
                                     "and 1 output, or with 2 inputs and 2 outputs.");

        props.add (new BooleanPropertyComponent (getPluginIsSynth(), "Plugin is a Synth", "Is a Synth"));
        props.getLast()->setTooltip ("Enable this if you want your plugin to be treated as a synth or generator. It doesn't make much difference to the plugin itself, but some hosts treat synths differently to other plugins.");

        props.add (new BooleanPropertyComponent (getPluginWantsMidiInput(), "Plugin Midi Input", "Plugin wants midi input"));
        props.getLast()->setTooltip ("Enable this if you want your plugin to accept midi messages.");

        props.add (new BooleanPropertyComponent (getPluginProducesMidiOut(), "Plugin Midi Output", "Plugin produces midi output"));
        props.getLast()->setTooltip ("Enable this if your plugin is going to produce midi messages.");

        props.add (new BooleanPropertyComponent (getPluginSilenceInProducesSilenceOut(), "Silence", "Silence in produces silence out"));
        props.getLast()->setTooltip ("Enable this if your plugin has no tail - i.e. if passing a silent buffer to it will always result in a silent buffer being produced.");

        props.add (new TextPropertyComponent (getPluginTailLengthSeconds(), "Tail Length (in seconds)", 12, false));
        props.getLast()->setTooltip ("This indicates the length, in seconds, of the plugin's tail. This information may or may not be used by the host.");

        props.add (new BooleanPropertyComponent (getPluginEditorNeedsKeyFocus(), "Key Focus", "Plugin editor requires keyboard focus"));
        props.getLast()->setTooltip ("Enable this if your plugin needs keyboard input - some hosts can be a bit funny about keyboard focus..");

        props.add (new TextPropertyComponent (getPluginAUExportPrefix(), "Plugin AU Export Prefix", 64, false));
        props.getLast()->setTooltip ("A prefix for the names of exported entry-point functions that the component exposes - typically this will be a version of your plugin's name that can be used as part of a C++ token.");

        props.add (new TextPropertyComponent (getPluginAUCocoaViewClassName(), "Plugin AU Cocoa View Name", 64, false));
        props.getLast()->setTooltip ("In an AU, this is the name of Cocoa class that creates the UI. Some hosts bizarrely display the class-name, so you might want to make it reflect your plugin. But the name must be "
                                     "UNIQUE to this exact version of your plugin, to avoid objective-C linkage mix-ups that happen when different plugins containing the same class-name are loaded simultaneously.");

        props.add (new TextPropertyComponent (getPluginRTASCategory(), "Plugin RTAS Category", 64, false));
        props.getLast()->setTooltip ("(Leave this blank if your plugin is a synth). This is one of the RTAS categories from FicPluginEnums.h, such as: ePlugInCategory_None, ePlugInCategory_EQ, ePlugInCategory_Dynamics, "
                                     "ePlugInCategory_PitchShift, ePlugInCategory_Reverb, ePlugInCategory_Delay, "
                                     "ePlugInCategory_Modulation, ePlugInCategory_Harmonic, ePlugInCategory_NoiseReduction, "
                                     "ePlugInCategory_Dither, ePlugInCategory_SoundField");
    }

    props.add (new TextPropertyComponent (getProjectPreprocessorDefs(), "Preprocessor definitions", 32768, false));
    props.getLast()->setTooltip ("Extra preprocessor definitions. Use the form \"NAME1=value NAME2=value\", using whitespace or commas to separate the items - to include a space or comma in a definition, precede it with a backslash.");

    for (int i = props.size(); --i >= 0;)
        props.getUnchecked(i)->setPreferredHeight (22);
}