Example #1
0
void Project::BuildConfiguration::createPropertyEditors (Array <PropertyComponent*>& props)
{
    props.add (new TextPropertyComponent (getName(), "Name", 96, false));
    props.getLast()->setTooltip ("The name of this configuration.");

    props.add (new BooleanPropertyComponent (isDebug(), "Debug mode", "Debugging enabled"));
    props.getLast()->setTooltip ("If enabled, this means that the configuration should be built with debug synbols.");

    const char* optimisationLevels[] = { "No optimisation", "Optimise for size and speed", "Optimise for maximum speed", 0 };
    const int optimisationLevelValues[] = { 1, 2, 3, 0 };
    props.add (new ChoicePropertyComponent (getOptimisationLevel(), "Optimisation", StringArray (optimisationLevels), Array<var> (optimisationLevelValues)));
    props.getLast()->setTooltip ("The optimisation level for this configuration");

    props.add (new TextPropertyComponent (getTargetBinaryName(), "Binary name", 256, false));
    props.getLast()->setTooltip ("The filename to use for the destination binary executable file. Don't add a suffix to this, because platform-specific suffixes will be added for each target platform.");

    props.add (new TextPropertyComponent (getTargetBinaryRelativePath(), "Binary location", 1024, false));
    props.getLast()->setTooltip ("The folder in which the finished binary should be placed. Leave this blank to cause the binary to be placed in its default location in the build folder.");

    props.add (new TextPropertyComponent (getHeaderSearchPath(), "Header search path", 16384, false));
    props.getLast()->setTooltip ("Extra header search paths. Use semi-colons to separate multiple paths.");

    props.add (new TextPropertyComponent (getBuildConfigPreprocessorDefs(), "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.");

    if (getMacSDKVersion().toString().isEmpty())
        getMacSDKVersion() = osxVersionDefault;

    const char* osxVersions[] = { "Use Default", osxVersion10_4, osxVersion10_5, osxVersion10_6, 0 };
    const char* osxVersionValues[] = { osxVersionDefault, osxVersion10_4, osxVersion10_5, osxVersion10_6, 0 };

    props.add (new ChoicePropertyComponent (getMacSDKVersion(), "OSX Base SDK Version", StringArray (osxVersions), Array<var> (osxVersionValues)));
    props.getLast()->setTooltip ("The version of OSX to link against in the XCode build.");

    if (getMacCompatibilityVersion().toString().isEmpty())
        getMacCompatibilityVersion() = osxVersionDefault;

    props.add (new ChoicePropertyComponent (getMacCompatibilityVersion(), "OSX Compatibility Version", StringArray (osxVersions), Array<var> (osxVersionValues)));
    props.getLast()->setTooltip ("The minimum version of OSX that the target binary will be compatible with.");

    const char* osxArch[] = { "Use Default", "Native architecture of build machine", "Universal Binary (32-bit)", "Universal Binary (64-bit)", "64-bit Intel", 0 };
    const char* osxArchValues[] = { osxArch_Default, osxArch_Native, osxArch_32BitUniversal, osxArch_64BitUniversal, osxArch_64Bit, 0 };

    if (getMacArchitecture().toString().isEmpty())
        getMacArchitecture() = osxArch_Default;

    props.add (new ChoicePropertyComponent (getMacArchitecture(), "OSX Architecture", StringArray (osxArch), Array<var> (osxArchValues)));
    props.getLast()->setTooltip ("The type of OSX binary that will be produced.");

    for (int i = props.size(); --i >= 0;)
        props.getUnchecked(i)->setPreferredHeight (22);
}
Example #2
0
void FW::profilePop(void)
{
    if (!s_profileStarted || s_profileStack.getSize() == 0)
        return;
    if (!Thread::isMain())
        fail("profilePop() can only be used in the main thread!");

    if (s_profileStack.getSize() > 1)
        s_profileTimers[s_profileStack.getLast()].timer.end();
    s_profileStack.removeLast();
    if (s_profileStack.getSize() == 1)
        s_profileTimers[s_profileStack.getLast()].timer.end();
}
Example #3
0
Vec2i GLContext::getStringSize(const String& str)
{
   // Split the string into lines.

    Array<String> lines;
    str.split('\n', lines, true);
    while (lines.getSize() && !lines.getLast().getLength())
        lines.removeLast();

    // Compute metrics.

    Vec2i strSize = 0;
    for (int i = 0; i < lines.getSize(); i++)
    {
        if (!lines[i].getLength())
            lines[i] = " "; // To avoid lineSize.y being zero.

    SIZE size;
		if (!GetTextExtentPoint32(m_memdc, lines[i].getPtr(), lines[i].getLength(), &size))
        failWin32Error("GetTextExtentPoint32");
        Vec2i lineSize(size.cx + m_vgFontMetrics.tmOverhang, size.cy);
        strSize.x = max(strSize.x, lineSize.x);
        strSize.y += lineSize.y;
}

	return strSize;
}
void ProjectExporter::createPropertyEditors (Array <PropertyComponent*>& props)
{
    props.add (new TextPropertyComponent (getTargetLocation(), "Target Project Folder", 1024, false));
    props.getLast()->setTooltip ("The location of the folder in which the " + name + " project will be created. This path can be absolute, but it's much more sensible to make it relative to the jucer project directory.");

    props.add (new TextPropertyComponent (getJuceFolder(), "Juce Location", 1024, false));
    props.getLast()->setTooltip ("The location of the Juce library folder that the " + name + " project will use to when compiling. This can be an absolute path, or relative to the jucer project folder, but it must be valid on the filesystem of the machine you use to actually do the compiling.");

    for (int i = 0; i < libraryModules.size(); ++i)
        libraryModules.getUnchecked(i)->createPropertyEditors (*this, props);

    props.add (new TextPropertyComponent (getExporterPreprocessorDefs(), "Extra 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.");

    props.add (new TextPropertyComponent (getExtraCompilerFlags(), "Extra compiler flags", 2048, false));
    props.getLast()->setTooltip ("Extra command-line flags to be passed to the compiler. This string can contain references to preprocessor definitions in the form ${NAME_OF_DEFINITION}, which will be replaced with their values.");
    props.add (new TextPropertyComponent (getExtraLinkerFlags(), "Extra linker flags", 2048, false));
    props.getLast()->setTooltip ("Extra command-line flags to be passed to the linker. You might want to use this for adding additional libraries. This string can contain references to preprocessor definitions in the form ${NAME_OF_VALUE}, which will be replaced with their values.");
}
Example #5
0
void FW::profilePush(const char* id)
{
    if (!s_profileStarted)
        return;
    if (!Thread::isMain())
        fail("profilePush() can only be used in the main thread!");

    // Find or create token.

    S32 token;
    S32* found = s_profilePointerToToken.search(id);
    if (found)
        token = *found;
    else
    {
        found = s_profileStringToToken.search(id);
        if (found)
            token = *found;
        else
        {
            token = s_profileStringToToken.getSize();
            s_profileStringToToken.add(id, token);
        }
        s_profilePointerToToken.add(id, token);
    }

    // Find or create timer.

    Vec2i timerKey(-1, token);
    if (s_profileStack.getSize())
        timerKey.x = s_profileStack.getLast();

    S32 timerIdx;
    found = s_profileTimerHash.search(timerKey);
    if (found)
        timerIdx = *found;
    else
    {
        timerIdx = s_profileTimers.getSize();
        s_profileTimerHash.add(timerKey, timerIdx);
        ProfileTimer& timer = s_profileTimers.add();
        timer.id = id;
        timer.parent = timerKey.x;
        if (timerKey.x != -1)
            s_profileTimers[timerKey.x].children.add(timerIdx);
    }

    // Push timer.

    if (s_profileStack.getSize() == 1)
        s_profileTimers[s_profileStack[0]].timer.start();
    s_profileStack.add(timerIdx);
    if (s_profileStack.getSize() > 1)
        s_profileTimers[timerIdx].timer.start();
}
void ComponentBuilder::updateChildComponents (Component& parent, const ValueTree& children)
{
    using namespace ComponentBuilderHelpers;

    const int numExistingChildComps = parent.getNumChildComponents();

    Array <Component*> componentsInOrder;
    componentsInOrder.ensureStorageAllocated (numExistingChildComps);

    {
        OwnedArray<Component> existingComponents;
        existingComponents.ensureStorageAllocated (numExistingChildComps);

        int i;
        for (i = 0; i < numExistingChildComps; ++i)
            existingComponents.add (parent.getChildComponent (i));

        const int newNumChildren = children.getNumChildren();
        for (i = 0; i < newNumChildren; ++i)
        {
            const ValueTree childState (children.getChild (i));

            ComponentBuilder::TypeHandler* const type = getHandlerForState (childState);
            jassert (type != nullptr);

            if (type != nullptr)
            {
                Component* c = findComponentWithID (existingComponents, getStateId (childState));

                if (c == nullptr)
                    c = createNewComponent (*type, childState, &parent);

                componentsInOrder.add (c);
            }
        }

        // (remaining unused items in existingComponents get deleted here as it goes out of scope)
    }

    // Make sure the z-order is correct..
    if (componentsInOrder.size() > 0)
    {
        componentsInOrder.getLast()->toFront (false);

        for (int i = componentsInOrder.size() - 1; --i >= 0;)
            componentsInOrder.getUnchecked(i)->toBehind (componentsInOrder.getUnchecked (i + 1));
    }
}
Example #7
0
void FW::popLogFile(void)
{
    s_lock.enter();
    if (s_logFiles.getSize())
    {
        s_logStreams.getLast()->flush();
        delete s_logFiles.removeLast();
        delete s_logStreams.removeLast();
        if (!s_logFiles.getSize())
        {
            s_logFiles.reset();
            s_logStreams.reset();
        }
    }
    s_lock.leave();
}
Example #8
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);
}
Example #9
0
Vec2i GLContext::drawLabel(const String& str, const Vec4f& pos, const Vec2f& align, U32 fgABGR, U32 bgABGR)
{
    // Split the string into lines.

    Array<String> lines;
    str.split('\n', lines, true);
    while (lines.getSize() && !lines.getLast().getLength())
        lines.removeLast();

    // Compute metrics.

    Vec2i strSize = 0;
    for (int i = 0; i < lines.getSize(); i++)
    {
        if (!lines[i].getLength())
            lines[i] = " "; // To avoid lineSize.y being zero.

        Vec2i lineSize = getStringSize(lines[i]);
        strSize.x = max(strSize.x, lineSize.x);
        strSize.y += lineSize.y;
    }

    // Empty or fully transparent => skip.

    if (strSize.x <= 0 || strSize.y <= 0 || ((fgABGR | bgABGR) & 0xFF000000) == 0)
        return strSize;

    // Initialize GL state.

    glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT);
    glEnable(GL_BLEND);
    glBlendEquation(GL_FUNC_ADD);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // Draw each line.

    Vec4f fgColor = Vec4f::fromABGR(fgABGR);
    Vec4f bgColor = Vec4f::fromABGR(bgABGR);
    Vec2f linePos(0.0f, (F32)strSize.y);

    for (int i = 0; i < lines.getSize(); i++)
    {
        Vec2i lineSize = (lines.getSize() == 1) ? strSize : getStringSize(lines[i]);
        if (lineSize.x <= 0 || lineSize.y <= 0)
            continue;

        linePos.y -= (F32)lineSize.y;
        const Vec2i& texSize = uploadString(lines[i], lineSize);

        Vec4f tpos = m_vgXform * pos;
        Vec2f pixel = m_viewScale * tpos.w;
        tpos.x += (linePos.x - align.x * (F32)lineSize.x) * pixel.x;
        tpos.y += (linePos.y - align.y * (F32)strSize.y) * pixel.y;
        tpos.x = floor((tpos.x + tpos.w) / pixel.x + 0.5f) * pixel.x - tpos.w;
        tpos.y = floor((tpos.y + tpos.w) / pixel.y + 0.5f) * pixel.y - tpos.w;

        if (bgColor.w > 0.0f)
            for (int j = -1; j <= 1; j++)
                for (int k = -1; k <= 1; k++)
                    drawString(tpos + Vec4f(Vec2f((F32)j, (F32)k) * pixel, 0.0f, 0.0f), lineSize, texSize, bgColor);

        if (fgColor.w > 0.0f)
            drawString(tpos, lineSize, texSize, fgColor);
    }

    // Clean up.

    glPopAttrib();
    checkErrors();
    return strSize;
}
Example #10
0
/**
 * Remove points in a signal based on the angle between adjacent segments in
 * the signal.  The end points of the signal are always retained.
 * 
 * @param aAngle If the angle between two adjacent segments is less than
 * aAngle the point in common between the two segments is removed.  This
 * is evaluate for each point in the signal.
 * @param rTime Array of time values.  This array is altered.
 * @param rSignal Array of signal values.  This array is altered.
 * @return Number of points removed.
 */
int Signal::
ReduceNumberOfPoints(double aDistance,
							Array<double> &rTime,Array<double> &rSignal)
{
	// CHECK SIZES
	int size = rTime.getSize();
	int sizeSignal = rSignal.getSize();
	if(size!=sizeSignal) {
		cout<<"\n\nSignal.ReduceNumberOfPoints:: quitting.  The time and signal ";
		cout<<"arrays have different numbers of points.\n\n";
		return(0);
	}

	// CHECK ANGLE
	if(aDistance<SimTK::Zero) aDistance = SimTK::Zero;

	// APPEND FIRST POINT
	Array<double> t(0.0,0,size),s(0.0,0,size);
	t.append(rSignal[0]);
	s.append(rSignal[0]);
	int iLast=0;

	// REMOVE POINTS
	int i,imid;
	SimTK::Vec3 p1(0.0,0.0,0.0);
	SimTK::Vec3 p2(0.0,0.0,0.0);
	SimTK::Vec3 p3(0.0,0.0,0.0);
	SimTK::Vec3 v1(0.0,0.0,0.0);
	SimTK::Vec3 v2(0.0,0.0,0.0);

	double tmid,mv1,mv2,cos,dsq;
	for(i=1;i<(size-1);i++) {

		// FIRST POINT
		// LAST POINT IN SIMPLIFIED ARRAY
		p1[0] = t.getLast();
		p1[1] = s.getLast();

		// THIRD POINT
		p3[0] = rTime[i+1];
		p3[1] = rSignal[i+1];

		// SECOND POINT
		// MIDPOINT
		tmid = 0.5*(p3[0]-p1[0]) + p1[0];
		imid = rTime.searchBinary(tmid,false,iLast,i+1);
		if(imid<=iLast) imid++;
		p2[0] = rTime[imid];
		p2[1] = rSignal[imid];

		v1 = p2 - p1; //Mtx::Subtract(1,3,p2,p1,v1);
		v2 = p3 - p1; //Mtx::Subtract(1,3,p3,p1,v2);

		mv1 = v1.norm(); //Mtx::Magnitude(3,v1);
		mv2 = v2.norm(); //Mtx::Magnitude(3,v2);
		cos = (~v1*v2)/(mv1*mv2); //Mtx::DotProduct(3,v1,v2) / (mv1*mv2); 

		dsq = mv1 * mv1 * (1.0 - cos*cos);

		if(dsq < (aDistance*aDistance)) continue;

		iLast = i;
		t.append(rTime[i]);
		s.append(rSignal[i]);
	}

	// APPEND ENDPOINT
	t.append(rTime.getLast());
	s.append(rSignal.getLast());

	// NUMBER REMOVED
	int numberRemoved = rTime.getSize() - t.getSize();

	// ALTER ARRAYS
	rTime = t;
	rSignal = s;

	return(numberRemoved);
}
Example #11
0
void GuiPiano::buttonClicked(Button *button)
{
    
    //get modifier key so we can handle cmd-clicks when selecting keys
    ModifierKeys modifier = ModifierKeys::getCurrentModifiers();
    
    
	for (int i = 0; i <= 119; i++)
	{
        if (button == keys[i])
        {
            //=========================================================================
            //=========================================================================
            //regular click to set the selected midi pads note or sequencers pad root note
            if (modifier.isAnyModifierKeyDown() == false)
            {
                //first clear all keys
                for (int i = 0; i < 120; i++)
                    setKeyDisplay(i, false);
                selectedKeys.clear();
                
                
                for (int padIndex = 0; padIndex < selectedPads.size(); padIndex++)
                {
                    int padNum = selectedPads[padIndex];
                    
                    //=========================================================================
                    //MIDI MODE REG CLICK
                    if (PAD_SETTINGS->getMode() == 1) //Midi Mode
                    {
                        PAD_SETTINGS->setMidiNote(i);
                        
                        if (padIndex == 0)
                        {
                            setKeyDisplay (i, true);
                            selectedKeys.addIfNotAlreadyThere(i);
                            noteNumber = i;
                        }
                    }
                    
                    //=========================================================================
                    //SEQ MODE REG CLICK
                    else if (PAD_SETTINGS->getMode() == 3) //Sequencer Mode
                    {
                        
                        //get currently set 'root' note
                        int rootNote = PAD_SETTINGS->getSequencerMidiNote(0);
                        //get difference between root note and clicked note
                        int transposeValue = rootNote - i;
                        
                        //check to see if the top row of grid will be transposed
                        //to above 119. If so, don't transpose the notes, and just
                        //redraw/re-set what was last there in the below else statement
                        if (PAD_SETTINGS->getSequencerMidiNote(11)-transposeValue <= 119)
                        {
                            //add the transpose value to each note in the scale/set
                            for (int row = 0; row < 12; row++)
                            {
                                int currentVal = PAD_SETTINGS->getSequencerMidiNote(row);
                                
                                if (currentVal >= 0)
                                {
                                    int newVal = currentVal-transposeValue;
                                    
                                    PAD_SETTINGS->setSequencerMidiNote(newVal, row);
                                    
                                    //update the GUI
                                    if (padIndex == 0)
                                    {
                                        setKeyDisplay (newVal, true);
                                        selectedKeys.addIfNotAlreadyThere(newVal);
                                    }
                                    
                                    if (row == 0)
                                        noteNumber = i;
                                }
                                
                            }
                        }
                        else
                        {
                            //redraw and re-set what was previously there
                            //bit convoluted to clear everything above
                            //just to redraw it in a certain situation.
                            //Is there a better way to code it?
                            for (int row = 0; row < 12; row++)
                            {
                                if (padIndex == 0)
                                {
                                    setKeyDisplay (PAD_SETTINGS->getSequencerMidiNote(row), true);
                                    selectedKeys.addIfNotAlreadyThere(PAD_SETTINGS->getSequencerMidiNote(row));
                                }
                            }
                            
                        }
                        
                        recentlyUpdated = true;
                         
                    }
                }
            
                
            }
            
            //=========================================================================
            //=========================================================================
            //cmd-click to select mutiple notes for midi pads or custom scale for sequencer pads
            else if (modifier.isCommandDown() == true)
            {
                //don't intially clear the keys
                
                //=========================================================================
                //MIDI MODE CMD-CLICK
                
                //if the number of selected keys is less than the number of selected pads
                if (selectedKeys.size() < selectedPads.size())
                {
                    //cycle through the SELECTED KEYS in the order they were selected,
                    //applying them to the selected pads in the order they were selected.
                    for (int padIndex = 0; padIndex < selectedKeys.size(); padIndex++)
                    {
                        int padNum = selectedPads[padIndex];
                        
                        if (PAD_SETTINGS->getMode() == 1) //Midi Mode
                        {
                            
                            PAD_SETTINGS->setMidiNote(selectedKeys[padIndex]);
                            
                            //update the GUI
                            if (padIndex == 0)
                            {
                                //add the key
                                setKeyDisplay (i, true);
                                selectedKeys.addIfNotAlreadyThere(i); 
                                noteNumber = selectedKeys[0];
                            }
                            
                        }
                        
                    }
                     
                }
        
                //=========================================================================
                //SEQ MODE CMD-CLICK
                
                for (int padIndex = 0; padIndex < selectedPads.size(); padIndex++)
                {
                    int padNum = selectedPads[padIndex];
                    
                    if (PAD_SETTINGS->getMode() == 3) //Sequencer Mode
                    {
                        /*
                         
                         Cmd-click is used to select a custom scale/set of notes for a the sequence grid of a sequencer pad.
                         Click on an unselected key to add it, click on a selected key to remove it.
                         The selected keys/notes will be applied in order of their value to the sequencer rows.
                         If less than 12 notes are selected, the top 'unselected' rows will note have any notes on them.
                         
                         This is the current way that the app handles command-clicks on the piano in seq mode:
                         
                         When the user cmd-clicks a key for the first time (when recentlyUpdated == true) it will clear the piano
                         and allow the user to select 12 individual different keys for each row if the sequence.
                         Each time a key is selected it orders the selectedkey array and
                         applies all the selected keys to the sequence rows.
                         If the number of selected keys is less than the number of rows (12), each row which
                         doesn't currently have a key selected for it is set to an 'off' value of -500.
                         I've chosen 500 as no degree of transposing a note set to -500 could be transposed to 
                         be positive by regualar clicking the piano).
                         The app will view any minus midi note number as 'off', whether its to display the note on the piano
                         or play the note as a midi message.
                         
                         This method seems to make more sense over the other possible methods:
                         1. any 'unchosen' note is set to a default note such as 0 or 60. This is flawed as when transposing
                         the selection it will transpose the default note which might not make sense, plus when
                         ordering the selected keys the default note could be layed out somewhere in the middle of the
                         selected notes, which doesn't make sense as any unselected notes should be set to the top of the grid.
                         2. any 'unchosen' note is kept the same as the previous note. This also flawed because of the 
                         second reason in the point above.
                         */
                        
                        //=========== click on unselected key ===============
                        
                        if (keys[i]->getToggleState() == true) //if was previous off and clicked
                        {
                            
                            if (recentlyUpdated == true && selectedKeys.size() == 12) // so th cmd-click doesn't delete if incomplete set
                            {
                                if (padIndex == 0)
                                {
                                    //clear all keys
                                    for (int i = 0; i < 120; i++)
                                        setKeyDisplay(i, false);
                                    selectedKeys.clear();
                                }
                                
                            }
                            
                            recentlyUpdated = false;
                            
                            //if the number of selected keys is less than the number of sequencer rows
                            if (selectedKeys.size() < 12)
                            {
                                //update the GUI
                                if (padIndex == 0)
                                {
                                    setKeyDisplay (i, true);
                                    selectedKeys.addIfNotAlreadyThere(i);
                                    
                                    //sort selectedKeys into order.
                                    //The below loop checks the recently added key/note
                                    //and compares in to the previous key and moves
                                    //it to the correct location in the array 
                                    
                                    for (int x = selectedKeys.size() - 1; x >= 0; x--)
                                    {
                                        if (selectedKeys[x] < selectedKeys[x-1])
                                        {
                                            selectedKeys.swap(x, x-1);
                                        }
                                    }
                                }
                                
                                for (int row = 0; row < 12; row++)
                                {
                                    int note = selectedKeys[row];
                                    
                                    if (row > selectedKeys.size()-1)
                                        note = -500; //'off' note
                                    
                                    PAD_SETTINGS->setSequencerMidiNote(note, row);
                                }
                                
                            }
                        }
                        
                        //=========== click on selected key ===============
                        
                        else if (keys[i]->getToggleState() == false) //if was previous on and clicked 
                        {
                            recentlyUpdated = false;
                            
                            //update the GUI (only need to do this a single time)
                            if (padIndex == 0)
                            {
                                setKeyDisplay (i, false);
                                selectedKeys.removeFirstMatchingValue(i);
                                
                                //Don't need to sort keys here do I? 
                                //Removing an element will resize the array,
                                //which will cause the top row to be set to note 'off'
                            }
                            
                            for (int row = 0; row < 12; row++)
                            {
                                int note = selectedKeys[row];
                                
                                if (row > selectedKeys.size()-1)
                                    note = -500; //'off' note
                                
                                PAD_SETTINGS->setSequencerMidiNote(note, row);
                            }
                         
                        }
                        
                        noteNumber = selectedKeys[0];
                    }
                }
            }
            
            //=========================================================================
            //=========================================================================
            //alt-click to transpose mutiple notes for midi pads
            else if (modifier.isAltDown() == true)
            {
                if (AppSettings::Instance()->padSettings[selectedPads[0]]->getMode() == 1) //Midi Mode
                {
                    //clear all keys
                    for (int i = 0; i < 120; i++)
                        setKeyDisplay(i, false);
                    selectedKeys.clear();
                    
                    //At the moment the currentl alg. belows won't allow you to transpose a scale
                    //if ANY note will be transposed to above 119. Also, when transposing the note
                    //you select will be the lowest note. However in the old software it was possible
                    //to transpose notational arrangements so that the bottom set of notes would all
                    //equal 0 or the top sets would all equal 119, meaning you could have more choice 
                    //over where the arrangment starts and ends. Do we want that here? If so, the below
                    //code will need to be changed to how it was before (most of it has just been
                    //commented out.
                    
                    //Get the 'root note'.
                    //Should the root note be the note of the first select pad (selectedPads[0]).
                    //Or should it be the lowest note?
                    //Below is the code to find the lowest note.
                    Array <int> selectedPadsNotes;
                    for (int padIndex = 0; padIndex < selectedPads.size(); padIndex++)
                        selectedPadsNotes.insert(padIndex, 
                                                 AppSettings::Instance()->padSettings[selectedPads[padIndex]]->getMidiNote());
                    DefaultElementComparator<int> sorter;
                    selectedPadsNotes.sort (sorter);
                    int rootNote = selectedPadsNotes[0];
                    
                    //get difference between root note and clicked note
                    int transposeValue = rootNote - i;
                    
                    
                    //check to see if the highest note will be transposed
                    //to above 119. If so, don't transpose the notes, and just
                    //redraw/re-set what was last there in the below else statement
                    if (selectedPadsNotes.getLast()-transposeValue <= 119)
                    {
                        for (int padIndex = 0; padIndex < selectedPads.size(); padIndex++)
                        {
                            int padNum = selectedPads[padIndex];
                            
                            int currentVal = PAD_SETTINGS->getMidiNote();
                            int newVal = currentVal-transposeValue;
                            
                             //if (newVal > 119)
                             //newVal = 119;
                             //else if (newVal < 0)
                             //newVal = 0;
                            
                            PAD_SETTINGS->setMidiNote(newVal);
                            
                            //update the GUI
                            setKeyDisplay (newVal, true);
                            selectedKeys.addIfNotAlreadyThere(newVal);
                            
                            if (padIndex == 0)
                                noteNumber = newVal;
                            
                        }
                    }
                    else
                    {
                        //redraw and re-set what was previously there
                        //bit convoluted to clear everything above
                        //just to redraw it in a certain situation.
                        //Is there a better way to code it?
                        for (int padIndex = 0; padIndex < selectedPads.size(); padIndex++)
                        {
                            int padNum = selectedPads[padIndex];
                            setKeyDisplay (PAD_SETTINGS->getMidiNote(), true);
                            selectedKeys.addIfNotAlreadyThere(PAD_SETTINGS->getMidiNote());
                            
                        }
                        
                    }
                    
                }
            }
               
            break;
            //=========================================================================
            //=========================================================================
        }
	}
}
Example #12
0
void ProcessorGraph::updateConnections(Array<SignalChainTabButton*, CriticalSection> tabs)
{
    clearConnections(); // clear processor graph

    std::cout << "Updating connections:" << std::endl;
    std::cout << std::endl;
    std::cout << std::endl;

    Array<GenericProcessor*> splitters;
    // GenericProcessor* activeSplitter = nullptr;

    for (int n = 0; n < tabs.size(); n++) // cycle through the tabs
    {
        std::cout << "Signal chain: " << n << std::endl;
        std::cout << std::endl;

        GenericEditor* sourceEditor = (GenericEditor*) tabs[n]->getEditor();
        GenericProcessor* source = (GenericProcessor*) sourceEditor->getProcessor();

        while (source != nullptr)// && destEditor->isEnabled())
        {
            std::cout << "Source node: " << source->getName() << "." << std::endl;
            GenericProcessor* dest = (GenericProcessor*) source->getDestNode();

            if (source->enabledState())
            {
                // add the connections to audio and record nodes if necessary
                if (!(source->isSink()     ||
                      source->isSplitter() ||
                      source->isMerger()   ||
                      source->isUtility())
                    && !(source->wasConnected))
                {
                    std::cout << "     Connecting to audio and record nodes." << std::endl;
                    connectProcessorToAudioAndRecordNodes(source);
                }
                else
                {
                    std::cout << "     NOT connecting to audio and record nodes." << std::endl;
                }

                if (dest != nullptr)
                {

                    while (dest->isMerger()) // find the next dest that's not a merger
                    {
                        dest = dest->getDestNode();

                        if (dest == nullptr)
                            break;
                    }

                    if (dest != nullptr)
                    {
                        while (dest->isSplitter())
                        {
                            if (!dest->wasConnected)
                            {
                                if (!splitters.contains(dest))
                                {
                                    splitters.add(dest);
                                    dest->switchIO(0); // go down first path
                                }
                                else
                                {
                                    int splitterIndex = splitters.indexOf(dest);
                                    splitters.remove(splitterIndex);
                                    dest->switchIO(1); // go down second path
                                    dest->wasConnected = true; // make sure we don't re-use this splitter
                                }
                            }

                            dest = dest->getDestNode();

                            if (dest == nullptr)
                                break;
                        }

                        if (dest != nullptr)
                        {

                            if (dest->enabledState())
                            {
                                connectProcessors(source, dest);
                            }
                        }

                    }
                    else
                    {
                        std::cout << "     No dest node." << std::endl;
                    }

                }
                else
                {
                    std::cout << "     No dest node." << std::endl;
                }
            }

            std::cout << std::endl;

            source->wasConnected = true;
            source = dest; // switch source and dest

            if (source == nullptr && splitters.size() > 0)
            {

                source = splitters.getLast();
                GenericProcessor* newSource;// = source->getSourceNode();

                while (source->isSplitter() || source->isMerger())
                {
                    newSource = source->getSourceNode();
                    newSource->setPathToProcessor(source);
                    source = newSource;
                }

            }

        } // end while source != 0
    } // end "tabs" for loop

} // end method