Lock Page Layout Example

This plug-in example "locks" the page layout. It uses a browser class to parse through the pages within the specified measure region. If no measure selection was specified by the user, the full document will be processed.

For the first measure at each page, the plug-in puts a 'Start New Page' attribute for that measure.


First, the class declaration of a custom iterator handler.

class FCMyIteratorHandler : public FCIteratorHandler
{
    bool lock;
    FCMusicRegion* pRegion;
public:    
    FCMyIteratorHandler(bool value, FCMusicRegion* pTheRegion) : FCIteratorHandler()
    {
        lock = value;
        pRegion = pTheRegion;
    }
 
    virtual bool Iterate(__FCBase* pObject);
};


The implementation of FCMyIteratorHandler::Iterate() provides the core functionality for the iterator handler. This code will be run once for each page when the browser runs.

Note that much of the functionality in this method actually deals with the Automatic Update Layout setting in Finale: data can be marked as "not updated" at any time, which means that for both the page data and measures a new page update much be required to get the required data.

bool FCMyIteratorHandler::Iterate(__FCBase* object)
{
    FCPage* pPage = (FCPage*) object;    
    FCStaffSystem staffsystem;
 
    /* Update the layout if necessary: */
    if (!pPage->GetFirstSystem()) pPage->UpdateLayout();
 
    if (staffsystem.Load(pPage->GetFirstSystem())) {
        twobyte measureno = staffsystem.GetFirstMeasure();
        if (!measureno)
        {
            /* Update the layout if necessary: */
            pPage->UpdateLayout();
            if (!staffsystem.Load(pPage->GetFirstSystem())) return true;
        }
        measureno = staffsystem.GetFirstMeasure();
        if (pRegion->IsMeasureIncluded(measureno)) {
            /* Set the page break if it's in the region that should be processed: */
            FCMeasure measure;
            if (measure.Load(measureno)) {
                measure.SetPageBreak(lock);
                measure.Save();
            }
        }
    }
    return true;  // Continue with next page
}


The code to browse through the pages and use the iterator handler becomes pretty simple. The browser is set up statically, which is used to call all pages by using the custom iterator object. The ForEach() method call (highlighted below) is the row where the iterator handler is activated.

void LockPages(FCMusicRegion* pRegion, bool lock)
{
    FCBrowserPages pages;        
    FCMyIteratorHandler *pMyIteratorHandler = new FCMyIteratorHandler(lock, pRegion);    
    pages.ForEach(pMyIteratorHandler);    delete pMyIteratorHandler;
}

 

Mute Notes Example

This plug-in will mute or turn on playback for entries in a selected region. To achieve this, very few lines of code is needed!


The class declaration of the custom iterator handler:

class FCEntryPlaybackIH : public FCIteratorHandler
{
    bool playback;
public:
    FCEntryPlaybackIH(bool shouldplayback) : FCIteratorHandler()
        { playback = shouldplayback; }
    virtual bool Iterate(__FCBase* object);
};


The implementation of the Iterate method. The method returns true to signal that the next entry whould be processed (resulting in that all entries are processed).

bool FCEntryPlaybackIH::Iterate(__FCBase* object)
{
    FCNoteEntry* pEntry = (FCNoteEntry*) object;
    if (pEntry->IsNote()) pEntry->SetPlayback(playback);
    return true;
}


The part that runs the iterator handler for the region looks like this. A browser is used for the note entries, since there's no need to collect all the entries into a collection. The playback parameter decides if the entries should be played back or be muted.

void MuteOrUnmuteNotes(FCMusicRegion* pRegion, bool playback)
{
    FCBrowserNoteEntries browser;
    FCEntryPlaybackIH myIteratorHandler(playback);
    myIteratorHandler.SetSaveAfterIterate(true);
    browser.ForEachInRegion(&myIteratorHandler, pRegion);
}

 

Double Barlines Example

This plug-in will put double barlines and break multi-measure rests at all key signature changes. It will not put double barlines when there's a minor/major key change but with accidentals unchanged, although this behavior is easy to change.

The example shows both the use of a collection class and a iterator handler. Please note that the implementation of the iterator handler assumes that a collection is used - it has to be modified if a browser class is used.


The definition the the iterator handler looks like this:

class FCDblBarlineIteratorHandler : public FCIteratorHandler
{
     FCKeySignature* pPrevKey; /* A pointer to the previous key sig */
     FCMeasure* pPrevMeasure;  /* A pointer to the previous
                               * measure in the measure collection */
public:
    FCDblBarlineIteratorHandler() : FCIteratorHandler()
    {
        pPrevKey = NULL;
        pPrevMeasure = NULL;
    }    
    virtual bool Iterate(__FCBase* pObject);
};



The implementation of the Iterate method in the iterator handler looks like this. If you would like the plug-in to put double barlines for any kind of key change (even when there's just a minor/major mode change), change the highlighted rows below into if ((pPrevKey->GetKeyID() != pNewKey->GetKeyID()).

Note that the implementation assumes that there's a collection of measures, since the pPrevMeasure will point to the previously measure processed in the collection. Also, please note that since the previous measure will still exist in the collection, the pointer to the previous key signature will also still be available.

bool FCDblBarlineIteratorHandler::Iterate(__FCBase* pObject)
{
    FCMeasure* pMeasure = (FCMeasure*) pObject;       
    FCKeySignature *pNewKey = pMeasure->GetKeySignature();
    if (pPrevKey)
    {
        if ((pPrevKey->CalcSharps() != pNewKey->CalcSharps()) ||
 (pPrevKey->CalcFlats() != pNewKey->CalcFlats()))
{ pPrevMeasure->SetBarline(FCMeasure::BARLINE_DOUBLE); pPrevMeasure->SetBreakMMRest(true); pPrevMeasure->Save(); } } pPrevKey = pNewKey; pPrevMeasure = pMeasure; return true; }


The code for using the iterator handler on a measure collection follows. It loads the measures in the supplied region, and then calls the Iterate method once for each measure.

void DoubleBarlines(FCMusicRegion* pRegion)
{
    FCMeasures measures;
    measures.LoadRegion(pRegion);
    FCDblBarlineIteratorHandler myIteratorHandler;
    measures.ForEach(&myIteratorHandler);
}

 

Dialog programming

To access the dialog classes, PDK_FRAMEWORK_DIALOGS code activation needs to be defined for the project.

In Windows, dialog resources are used. On the Mac, NIBs are used.

Collection class

A collection class stores objects of the same kind in a collection, where each item can be identified by an index. It's very similar to an C++ array.

Browser class 

A browser class is a bit similar to a collection class. The difference is that while the a collection will keep all its items like an array, the browser class will not store any items in a permanent location.

The browser class parses through the Finale database, one item at a time.

A browser class are more memory efficient than a collection class, but it can get more time-consuming if the same records need processing more than once.

At some occasions browser classes are a superior choice, for example:

  • When the data objects need to be processed only once

  • When searching the Finale database for specific information

The Lock Page Layout Example shows the browser class in action. Here the browser approach was chosen, since each page only need to be processed once.

The most common method to use a browse class is with the ForEach method, since a browser class doesn't provide as many iteration methods as a collection class.

 

Iterator handler

Iterator handlers were inspired by the code block (or closure) concept in the great Ruby script programming language. They provide a mechanism to separate functionality from data storage in "collection-type" classes. With iterator handles, you first decide in what way to parse the collection, then you "send" the processing functionality to that particular parser.

Iterator handlers are used by both collection classes and browser classes. If the implementation of the iterator handler doesn't assume that the supplied data is stored in a certain way, iterator handles can be used interchangeably by both collection classes and browser classes.

Please note that iterator handlers are not covered by the type-safe linkage in C++. It's up to the programmer to make sure that the object type passed to the iterator handler is a known type. For example, sending measure objects to an iterator handle that assumes staff objects will most likely crash.

 

NetBeans IDE (Windows)

Since NetBeans is made in Java and is portable between platform, similar instructions shuld work on Netbeans for Mac as well.

Main Documentation

The main reference for the Finale PDK is available at:
http://www.finaletips.nu/frameworkref/

Here you'll find documentation about classes, constants, hierarchies, and so on.

Framework design concepts

Compatibility

  • Ideally, the framework should compile and work with any version of the Finale PDK. Currently, the framework is compatible with the 2010PDK and 2012PDK. Generally, a higher PDK version is required if newer Finale features are needed. It's possible to create plug-ins that's runnable on earlier Finale versions than the PDK version, and the framework handle the version differences between the PDK version and the running Finale version.

  • String handling is handled automatically by the framework, though the FCString class (instead of char* for example). If Unicode is available (by the running Finale version and the PDK), the framework will use it. For example: if you're using the 2010PDK, Unicode will never be used (even on Finale versions that have Unicode support). And if you use the 2012PDK, Unicode will not be used by the framework if the plug-in is run on Finale 2011.

Classes

  • Class definitions should follow the naming conventions

  • Groups of classes that aren't almost always used by plug-ins should be activated by #defines to avoid code bloat

Finale API calls

  • Finale API calls should be encapsulated into relevant classes, instead of called directly.

Documentation

  • All documentation (Doxygen syntax) is put in the C++ header files.

  • Documentation is put before the definition/declaration.

  • Each definition that's documented should have a short \brief declaration. Any additional documentation goes in the next paragraph.

  • Parameters should be documented with a \param declaration

  • Return values should be documented with a \return declaration

  • Every class should belong to at least one group (the \ingroup declaration). The groups are defined in the pdkframework.h file.

 

Naming conventions

Naming Conventions for classes

  • All framework classes starts with the prefix FC. For example: FCString, FCMeasure, FCNote.

  • Appart from the FC prefix, a class name is in CamelCase. For example: FCStaffStyleDef, FCNoteEntry, FCTextExpressionDef.

  • Abstract classes that never should be used directly by a plug-in starts with the prefix __FC. For example: __FCBase, __FCBaseData, __FCNoInciOther.

  • Data collection classes specific to a type of object, has a plural s, compared to the object's class. For example: the collection class version of the FCPage class is FCPages.

  • Data browser classes specific to a type of object is named like the "collection version", but with the added suffix Browser. For example: the browser class version of the FCPage class is FCPagesBrowser.

  • In general, words are fully spelled out (and not abbreviated) in classes, if the word describes what the class mainly contains. The suffix Definition is always abbreviated as Def.

Naming Conventions for class methods

  • Names are in CamelCase

  • Methods intended for internal use start with an underscore character: '_'

  • Methods that return data values (that doesn't need to be deleted from heap) start with the prefix Get

  • Methods that create object(s) that must be deleted from the heap start with the prefix Create

  • Methods that set data values start with the prefix Set

  • Methods that is a boolean query start with the prefix Is

Naming Conventions for class members

  • Methods intended for internal use start with an underscore character: '_'

Code activation

Some of the classes or methods require code activation through #defines for the whole project. This makes the small, basic plug-ins much smaller.

  • PDK_FRAMEWORK_DEBUG - Debug methods for debugging support in the base classes, such as DebugOutDigit(), DebugOutBlock(), etc. On Windows, the DebugOutxxxx methods outputs to a separate console window. On the Mac, these methods goes to the console (within XCode for example).

  • PDK_FRAMEWORK_ENTRIES - Support for note entries and all related classes (such as note cells, layers, note-attached data).
  • PDK_FRAMEWORK_LAYOUT - Support for layout classes, such as FCPage and FCStaffSystem. FCMeasure is supported without this #define.
  • PDK_FRAMEWORK_PREFS - Access to the document preference settings classes
  • PDK_FRAMEWORK_DIAGNOSE - Automatic and detailed debug support for diagnostic purposes. If an operation fails, this option will output much information about the error. The PDK_FRAMEWORK_DEBUG #define must be set as well.
  • PDK_FRAMEWORK_FORMAT - Adds support for "Format" methods (that use the same syntax as the printf statement in C).
  • PDK_FRAMEWORK_SMARTSHAPES - Enables support for smart shapes.
  • PDK_FRAMEWORK_DIALOGS - Enables support for the dialog UI.
  • PDK_FRAMEWORK_ENIGMASTRINGS - Enables support for Enigma raw string methods in the string classes.
  • PDK_FRAMEWORK_SHAPES - Enable support for parsing and creation of shapes.
  • PDK_FRAMEWORK_COMPOSITETIMESIGS - Enable support for composite time signatures.
  • PDK_FRAMEWORK_NVWA - Enables cross-platform memory leak code through the "Stones of Nvwa" project on sourceforge: (http://sourceforge.net/projects/nvwa/). The project must link the debug_new.cpp file from that project.

 

Description

The Finale PDK Framework is a purely object-oriented layer around the Finale PDK to simplify plug-in programming for the Finale music notation product. Although the framework uses the Finale PDK to provide its function, very little knowledge about the Finale PDK should be required. One aim of the framework is to be fully documented all by itself.

The framework is also designed to provide possible hooks to object-oriented script languages like Ruby or Python.

The aims of the framework are:

  • to provide a very fast method to create Finale plug-ins

  • to provide logic and take care of complexities for the plug-in programmer

  • to provide excellent documentation to the programmer

  • to have a stable and easy maintainable code base

  • to be independent of the underlying Finale PDK version

  • to be able to create plug-ins that runs independently of the running Finale version

Requirements

This is the basic requirements for develop plug-ins with the Finale PDK Framework:

  • [C++] programming knowledge

  • A C++ development environment for Windows or Mac

  • A version of the Finale PDK Framework

  • A compatible version (PDK2010 or PDK2012) of the Finale PDK (from MakeMusic)

  • A version of Finale, to be able to test the plug-ins

Plugin

A Finale plug-in is a small program file that is loaded into Finale when Finale starts. A plug-in can expand Finale's functionality to the user.