Pinnacle Systems Sibelius - 7.5 User Manual

Using the ManuScript language
Written by Jonathan Finn, James Larcombe, Yasir Assam, Simon Whiteside, Mike Copperwhite, Paul Walmsley, Graham Westlake and Michael Eastwood, with contributions from Andrew Davis and Daniel Spreadbury.
Legal Notices
This product is subject to the terms and conditions of a software license agreement.
Avid, Sibelius and Scorch are registered trademarks of Avid Technology, Inc. in the USA, UK and other countries. All other trademarks are acknowledged as the property of their respective owners.
Product features, specifications, system requirements, and availability are subject to change without notice.
2
Contents
Introduction................................................................................................................................................................................................ 5
Tutorial 7
Edit Plug-ins................................................................................................................................................................................................8
Loops ......................................................................................................................................................................................................... 13
Objects ....................................................................................................................................................................................................... 15
Representation of a score ......................................................................................................................................................................... 17
The “for each” loop................................................................................................................................................................................... 19
Indirection, sparse arrays and user properties....................................................................................................................................... 21
Dialog editor.............................................................................................................................................................................................. 25
Debugging your plug-ins..........................................................................................................................................................................29
Storing and retrieving preferences .......................................................................................................................................................... 30
Reference 35
Syntax ........................................................................................................................................................................................................ 36
Expressions ...............................................................................................................................................................................................38
Operators................................................................................................................................................................................................... 40
Object Reference 41
Hierarchy of objects.................................................................................................................................................................................. 42
All objects ..................................................................................................................................................................................................43
Accessibility ..............................................................................................................................................................................................45
Bar..............................................................................................................................................................................................................46
Barline ....................................................................................................................................................................................................... 52
Barlines...................................................................................................................................................................................................... 53
BarObject...................................................................................................................................................................................................54
BarRest ...................................................................................................................................................................................................... 57
Bracket.......................................................................................................................................................................................................58
BracketsAndBraces...................................................................................................................................................................................59
Clef .............................................................................................................................................................................................................60
Comment...................................................................................................................................................................................................61
ComponentList ......................................................................................................................................................................................... 62
Component................................................................................................................................................................................................ 63
DateTime................................................................................................................................................................................................... 64
Dictionary.................................................................................................................................................................................................. 65
DocumentSetup ........................................................................................................................................................................................66
DynamicPartCollection............................................................................................................................................................................ 68
DynamicPart ............................................................................................................................................................................................. 69
EngravingRules......................................................................................................................................................................................... 70
File.............................................................................................................................................................................................................. 72
Folder.........................................................................................................................................................................................................73
GuitarFrame..............................................................................................................................................................................................74
GuitarScaleDiagram .................................................................................................................................................................................77
HitPointList...............................................................................................................................................................................................78
HitPoint.....................................................................................................................................................................................................79
InstrumentChange.................................................................................................................................................................................... 80
3
InstrumentTypeList..................................................................................................................................................................................81
InstrumentType........................................................................................................................................................................................ 82
KeySignature .............................................................................................................................................................................................84
Line ............................................................................................................................................................................................................ 85
LyricItem ...................................................................................................................................................................................................86
NoteRest .................................................................................................................................................................................................... 87
Note............................................................................................................................................................................................................ 90
NoteSpacingRule....................................................................................................................................................................................... 92
PageNumberChange.................................................................................................................................................................................94
PluginList ..................................................................................................................................................................................................95
Plugin......................................................................................................................................................................................................... 96
RehearsalMark ..........................................................................................................................................................................................97
Score .......................................................................................................................................................................................................... 98
Selection ..................................................................................................................................................................................................105
Sibelius..................................................................................................................................................................................................... 108
SoundInfo................................................................................................................................................................................................ 116
SparseArray............................................................................................................................................................................................. 117
Staff..........................................................................................................................................................................................................119
Syllabifier.................................................................................................................................................................................................122
SymbolItem and SystemSymbolItem....................................................................................................................................................123
SystemObjectPositions...........................................................................................................................................................................124
SystemStaff, Staff, Selection, Bar and all BarObject-derived objects.................................................................................................. 125
SystemStaff.............................................................................................................................................................................................. 126
Text and SystemTextItem ......................................................................................................................................................................127
TimeSignature......................................................................................................................................................................................... 128
TreeNode................................................................................................................................................................................................. 129
Tuplet....................................................................................................................................................................................................... 130
Utils..........................................................................................................................................................................................................131
VersionHistory........................................................................................................................................................................................ 136
Version ....................................................................................................................................................................................................137
VersionComment ................................................................................................................................................................................... 138
Global constants 139
What’s new in Sibelius 7 164
4

Introduction

ManuScript is a simple, music-based programming language developed to write plug-ins for the Sibelius music processor. The name was invented by Ben Sloman, a friend of Ben Finn’s.
It is based on Simkin, an embedded scripting language developed by Simon Whiteside, and has been extended by him and the rest of the Sibelius team ever since. (Simkin is a spooky pet name for Simon sometimes found in Victorian novels.) For more information on Simkin, and additional help on the language and syntax, go to the Simkin website at www.simkin.co.uk.

Rationale

In adding a plug-in language to Sibelius we were trying to address several different issues:
*
Music notation is complex and infinitely extensible, so some users will sometimes want to add to a music notation program to make it cope with these new extensions.
*
It is useful to allow frequently repeated operations (e.g. opening a MIDI file and saving it as a score) to be automated, using a system of scripts or macros.
*
Certain more complex techniques used in composing or arranging music can be partly automated, but there are too many to include as standard features in Sibelius.
There were several conditions that we wanted to meet in deciding what language to use:
*
The language had to be simple, as we want normal users (not just seasoned programmers) to be able to use it.
*
We wanted plug-ins to be usable on any computer, as the use of computers running both Windows and Mac OS X is widespread in the music world.
*
We wanted the tools to program in the language to be supplied with Sibelius.
*
We wanted musical concepts (pitch, notes, bars) to be easily expressed in the language.
*
We wanted programs to be able to talk to Sibelius easily (to insert and retrieve information from scores).
*
We wanted simple dialog boxes and other user interface elements to be easily programmed.
C/C++, the world’s “standard” programming language(s), were unsuitable as they are not easy for the non-specialist to use, they would need a separate compiler, and you would have to recompile for each different platform you wanted to support (and thus create multiple versions of each plug-in).
The language Java was more promising as it is relatively simple and can run on any platform without recompilation. However, we would still need to supply a compiler for people to use, and we could not express musical concepts in Java as directly as we could with a new language.
So we decided to create our own language that is interpreted so it can run on different platforms, integrated into Sibelius without any need for separate tools, and can be extended with new musical concepts at any time.
The ManuScript language that resulted is very simple. The syntax and many of the concepts will be familiar to programmers of C/ C++ or Java. Built into the language are musical concepts (Score, Staff, Bar, Clef, NoteRest) that are instantly comprehensible.

Technical support

Since the ManuScript language is more the province of our programmers than our technical support team (who are not, in the main, programmers), we can’t provide detailed technical help on it, any more than Oracle will help you with Java programming. This document and the sample plug-ins should give you a good idea of how to do some simple programming fairly quickly.
We would welcome any useful plug-ins you write – email them to daniel.spreadbury@avid.com and we may put them on our web site; if we want to distribute the plug-in with Sibelius itself, we’ll pay you for it.

Mailing list for plug-in developers

There is a growing community of plug-in developers working with ManuScript, and they can be an invaluable source of help when writing new plug-ins. To subscribe, go to http://avid-listsrv1.avid.com/mailman/listinfo/plugin-dev.
6

Tutorial

Tutorial

Edit Plug-ins

A simple plug-in

Let’s start a simple plug-in. You are assumed to have some basic experience of programming (e.g. in BASIC or C), so you’re already familiar with ideas like variables, loops and so on.
*
Start Sibelius.
*
Choose File> Plug-ins> Edit Plug-ins. The following dialog appears:
*
Now click New.
*
You are asked to type the internal name of your plug-in (used as the plug-in’s filename), the name that should appear on the menu and the name of the category in which the plug-in should appear, which will determine which ribbon tab it appears on.
The reason for having two separate names for plug-ins is that filenames may be no longer than 31 characters on Macs running Mac OS 9 (which is only significant if you intend your plug-in to be used with versions of Sibelius prior to Sibelius 4), but the menu names can be as long as you like.
*
Ty pe Tes t as the internal name, Test plug-in as the menu name and Tes ts as the category name, then click OK.
*
You’ ll se e Test (user copy) added to the list in the Edit Plug-ins dialog under a new Tes ts branch of the tree view. Click Close. This shows the folder in which the plug-in is located (Tes ts , which Sibelius has created for you), the filename of the
plug-in (minus the standard .plg file extension), and (user copy) tells you that this plug-in is located in your user application data folder, not the Sibelius program folder or application package itself.
*
If you look in the Home> Plug-ins gallery again you’ll see a Tes ts category, with a Tes t plug-in underneath it.
8
Edit Plug-ins
*
Choose Home> Plug-ins> Tes ts> Test and the plug-in will run. You may first be prompted that you cannot undo plug-ins, in which case click Yes to continue (and you may wish to switch on the Don’t say this again option so that you’re not both­ered by this warning in future.) What does our new Tes t plug-in do? It just pops up a dialog which says Tes t (whenever you start a new plug-in, Sibelius automatically generates in a one-line program to do this). You’ll also notice a window appear with a button that says Stop Plug-in, which appears whenever you run any plug-in, and which can be useful if you need to get out of a plug-in you’re working on that is (say) trapped in an infinite loop.
*
Click OK on the dialog and the plug-in stops.

Three types of information

Let’s look at what’s in the plug-in so far. Choose File > Plug-ins> Edit Plug-ins again, then select Tests/Test (user copy) from the list information that can make up a plug-in:
and click Edit (or simply double-click the plug-in’s name to edit it). You’ll see a dialog showing the three types of
*
Methods: similar to procedures, functions or routines in some other languages.
*
Dialogs: the layout of any special dialogs you design for your plug-in.
*
Data: variables whose value is remembered between running the plug-in. You can only store strings in these variables, so they’re useful for things like user-visible strings that can be displayed when the plug-in runs. For a more sophisticated approach to global variables, ManuScript provides custom user properties for all objects – see
User properties
on page 22.

Methods

The actual program consists of the methods. As you can see, plug-ins normally have at least two methods, which are created automatically for you when you create a new plug-in:
*
Initialize: this method is called automatically whenever you start up Sibelius. Normally it does nothing more than add the name of the plug-in to the Plug-ins menu, although if you look at some of the supplied plug-ins you’ll notice that it’s some­times also used to set default values for data variables.
*
Run: this is called when you run the plug-in, you’ll be startled to hear (it’s like
>
when you choose Home
Plug-ins> Te sts> Te st, the plug-in’s Run method is called. If you write any other methods, you
have to call them from the Run method – otherwise how can they ever do anything?
main()
in C/C++ and Java). In other words,
9
Tutorial
Click on Run, then click Edit (or you can just double-click Run to edit it). This shows a dialog where you can edit the Run method:
In the top field you can edit the name; in the next field you can edit the parameters (i.e. variables where values passed to the method are stored); and below is the code itself:
Sibelius.MessageBox("Test");
This calls a method
MessageBox
which pops up the dialog box that says Tes t when you run the plug-in. Notice that the method
name is followed by a list of parameters in parentheses. In this case there’s only one parameter: because it’s a string (i.e. text) it’s in double quotes. Notice also that the statement ends in a semicolon, as in C/C++ and Java. If you forget to type a semicolon, you’ll get an error when the plug-in runs.
What is the role of the word Sibelius in
Sibelius.MessageBox
? In fact it’s a variable representing the Sibelius program; the statement is telling Sibelius to pop up the message box (C++ and Java programmers will recognize that this variable refers to an “object”). If this hurts your brain, we’ll go into it later.

Editing the code

Now try amending the code slightly. You can edit the code just like in a word processor, using the mouse and arrow keys, and you
X
can also also use Ctrl+X/C/V or (Mac) you get a menu with these basic editing operations on them too.
Change the code to this:
x = 1;
x = x + 1;
Sibelius.MessageBox("1 + 1 = " & x);
You can check this makes sense (or, at least, some kind of sense) by clicking the Check syntax button. If there are any blatant mistakes (e.g. missing semicolons) you’ll be told where they are.
Then close the dialogs by clicking OK, OK again then Close. Run your amended plug-in from the Plug-ins menu and a message box with the answer
X/C/V for cut, copy and paste respectively. If you right-click (Windows) or Control-click
1 + 1 = 2
should appear.
How does it work? The first two lines should be obvious. The last line uses
&
to stick two strings together. You can’t use + as this
works only for numbers (if you try it in the example above, you’ll get an interesting answer!).
One pitfall: try changing the second line to:
x += 1;
then click Check syntax. You’ll get an error: this syntax (and the syntax ManuScript. You have to do
x = x+1;
.
x++
) is allowed in various languages but not in

Where plug-ins are stored

Plug-ins supplied with Sibelius are stored in folders buried deep within the Sibelius program folder on Windows, and inside the application package (or “bundle”) on Mac. It is not intended that end users should add extra plug-ins to these locations
10
Edit Plug-ins
themselves, as we have provided a per-user location for plug-ins to be installed instead. When you create a new plug-in or edit an existing one, the new or modified plug-in will be saved into the per-user location (rather than modifying or adding to the plug-ins in the program folder or bundle):
*
On Windows, additional plug-ins are stored at C:\Users\username\AppData\Roaming\Avid\Sibelius 7\Plugins.
*
On Mac, additional plug-ins are stored in subfolders at /Users/username/Library/Application Support/Avid/ Sibelius 7/Plugins.
This is worth knowing if you want to give a plug-in to someone else. The plug-ins appear in subfolders which correspond to the categories in which they appear in the various Plug-ins galleries. The filename of the plug-in itself is the plug-in’s internal name plus the .plg extension, e.g. Te st. pl g.
>
(Sibelius includes an automatic plug-in installer, which you can access via File
Plug-ins> Install Plug-ins. This makes it
easy to download and install plug-ins from the Sibelius web site.)

Line breaks and comments

As with C/C++ and Java, you can put new lines wherever you like (except in the middle of words), as long as you remember to put a semicolon after every statement. You can put several statements on one line, or put one statement on several lines.
//
You can add comments to your program, again like C/C++ and Java. Anything after
/*
between
and */ is ignored, whether just part of a line or several lines:
// comment lasts to the end of the line /* you can put several lines of comments here */
is ignored to the end of the line. Anything
For instance:
Sibelius.MessageBox("Hi!"); // print the active score
or:
Sibelius /* this contains the application */ .MessageBox("Hi!");

Varia bles

x
in the Test plug-in is a variable. In ManuScript a variable can be any sequence of letters, digits or _ (underscore), as long as it
doesn’t start with a digit.
A variable can contain an integer (whole number), a floating point number, a string (text) or an object (e.g. a note) – more about objects in a moment. Unlike most languages, in ManuScript a variable can contain any type of data – you don’t have to declare what type you want. Thus you can store a number in a variable, then store some text instead, then an object. Try this:
x = 56; x = x+1; Sibelius.MessageBox(x); // prints '57' in a dialog box x = "now this is text"; // the number it held is lost Sibelius.MessageBox(x); // prints 'now this is text' in a dialog x = Sibelius.ActiveScore; // now it contains a score Sibelius.MessageBox(x); // prints nothing in a dialog
Variables that are declared within a ManuScript method are local to that method; in other words, they cannot be used by other methods in the same plug-in. Global Data variables defined using the plug-in editor can be accessed by all methods in the plug­in, and their values are preserved over successive uses of the plug-in.
A quick aside about strings in ManuScript is in order at this point. Like many programming languages, ManuScript strings uses
\
the back-slash
\'
, and to include a new line you should use \n. Because of this, to include the backslash itself in a ManuScript string one has
use to write
\\
as an “escape character” to represent certain special things. To include a single quote character in your strings,
.

Converting between numbers, text and objects

Notice that the method
MessageBox
call to
MessageBox
is expecting to be sent some text to display. If you give it a number instead (as in the first
above) the number is converted to text. If you give it an object (such as a score), no text is produced.
11
Tutorial
Similarly, if a calculation is expecting a number but is given some text, the text will be converted to a number:
x = 1 + "1"; // the + means numbers are expected
Sibelius.MessageBox(x); // displays '2'
If the text doesn’t start with a number (or if the variable contains an object instead of text), it is treated as 0:
x = 1 + "fred";
Sibelius.MessageBox(x); // displays ‘1’
12

Loops

“for” and “while”

ManuScript has a plug-in called Potato. This is going to amuse one and all by writing the words of the well-known song “1 potato, 2 potato, 3 potato, 4”. Type in the following for the Run method of the new plug-in:
x = 1; while (x<5) {
}
Run it. It should display “1 potato,” “2 potato,” “3 potato,” “4 potato,” which is a start, though annoyingly you have to click OK after each message.
while
The semicolon after the final compulsory (you can’t omit them if they only contain one statement). Moreover, each block must contain at least one statement. We did say that ManuScript was a simple language.
while
loop which repeatedly executes a block of code until a certain expression becomes True. Create a new
text = x & " potato,"; Sibelius.MessageBox(text); x = x+1;
statement is followed by a condition in
}
brace). While the condition is true, the block is executed. Unlike some other languages, the braces are
( )
parentheses, then a block of statements in
{ }
braces (you don’t need a
Loops
x
In this example you can see that we are testing the value of common construct could be expressed more concisely in ManuScript by using a
at the start of the loop, and increasing the value at the end. This
for
loop. The above example could also be
written as follows:
for x = 1 to 5 {
text = x & " potato,"; Sibelius.MessageBox(text);
}
Here, the variable x is stepped from the first value (1) up to the end value (5), stopping one step before the final value. By default, the “step” used is 1, but we could have used (say) 2 by using the syntax
for x = 1 to 5 step 2
, which would then print
only “1 potato” and “3 potato”!
&
Notice the use of
to add strings. Because a string is expected on either side, the value of x is turned into a string.
Notice also we’ve used the Tab key to indent the statements inside the loop. This is a good habit to get into as it makes the structure clearer. If you have loops inside loops you should indent the inner loops even more.

The if statement

Now we can add an if statement so that the last phrase is just “4,” not “4 potato”:
x = 1; while (x<5) {
if(x=4) {
text = x & "."; } else {
text = x & " potato,"; } Sibelius.MessageBox(text); x = x+1;
}
13
Tutorial
if
The rule for
takes the form
executed if the condition is false. As with
if (
condition
while
) {
statements}. You can also optionally add
, the parentheses and braces are compulsory, though you can make the program
shorter by putting braces on the same line as other statements:
x = 1; while (x<5) {
if(x=4) {
text = x & "."; } else {
text = x & " potato,"; } Sibelius.MessageBox(text); x = x+1;
}
The position of braces is entirely a matter of taste.
Now let’s make this plug-in really cool. We can build up the four messages in a variable called
if
and
saving valuable wear on your mouse button. We can also switch round the
for
we return to the
text = ""; // start with no text for x = 1 to 5 {
if (not(x=4)) {
} else {
}
}
syntax we looked at earlier.
text = text & x & " potato, "; // add some text
text = text & x & "."; // add no. 4
else
else {
text
, and only display it at the end,
statements}, which is
blocks to show off the use of
not
. Finally,
Sibelius.MessageBox(text); // finally display it

Arithmetic

We’ve been using + without comment, so here’s a complete list of the available arithmetic operators:
a + b
a - b
a * b
a / b
a % b
-a
(a)
ManuScript evaluates operators strictly from left-to-right, unlike many other languages; so might expect. To get the answer 14, you’d have to write
ManuScript also supports floating point numbers, so whereas in some early versions
1.5. Conversion from floating point numbers to integers is achieved with the
Round(
expr)functions, which can be applied to any expression.
add
subtract
multiply
divide
remainder
negate
evaluate first
2+(3*4)
.
3/2
would work out as 1, it now evaluates to
RoundUp(
2+3*4
evaluates to 20, not 14 as you
expr),
RoundDown(
expr) and
14

Objects

Now we come to the neatest aspect of object-oriented languages like ManuScript, C++ or Java, which sets them apart from traditional languages like BASIC, Fortran and C. Variables in traditional languages can hold only certain types of data: integers, floating point numbers, strings and so on. Each type of data has particular operations you can do to it: numbers can be multiplied and divided, for instance; strings can be added together, converted to and from numbers, searched for in other strings, and so on. But if your program deals with more complex types of data, such as dates (which in principle you could compare using convert to and from strings, and even subtract) you are left to fend for yourself.
Object-oriented languages can deal with more complex types of data directly. Thus in the ManuScript language you can set a variable, let’s say
thischord.AddNote(60); // adds middle C (note no. 60) thischord.AddNote(64); // adds E (note no. 64)
thischord
, to be a chord in your score, and (say) add more notes to it:
If this seems magic, it’s just analogous to the kind of things you can do to strings in BASIC, where there are very special operations which apply to text only:
A$ = "1" A$ = A$ + " potato, ": REM add strings X = ASC(A$): REM get first letter code
In ManuScript you can set a variable to be a chord, a note in a chord, a bar, a staff or even a whole score, and do things to it. Why would you possibly want to set a variable to be a whole score? So you can save it or add an instrument to it, for instance.
=, <
Objects
and >,

Objects in action

We’ll have a look at how music is represented in ManuScript in a moment, but for a little taster, let’s plunge straight in and adapt Potato to create a score:
x = 1; text = ""; // start with no text while (x<5) {
if (not(x=4)) {
text = text & x & " potato, "; // add some text } else {
text = text & x & "."; // add no. 4 } x = x+1;
}
Sibelius.New(); // create a new score newscore = Sibelius.ActiveScore; // put it in a variable newscore.CreateInstrument("Piano"); staff = newscore.NthStaff(1); // get top staff bar = staff.NthBar(1); // get bar 1 of this staff bar.AddText(0,text,"Technique"); // use Technique text style
This creates a score with a Piano, and types our potato text in bar 1 as Technique text.
The code uses the period ( that the variable before the period has to contain an object.
.
) several times, always in the form
variable.variable
or
variable.method()
. This shows
*
If there’s a variable name after the period, we’re getting one of the object’s sub-variables (called “fields” or “member variables” in
n
some languages). For instance, if 60 for middle C), and
n.Name
is a variable containing a note, then
is a string describing its pitch (e.g. “C4” for middle C). The variables available for each type of
n.Pitch
is a number representing its MIDI pitch (e.g.
object are listed later.
*
If there’s a method name after the period (followed by () parentheses), one of the methods allowed for this type of object is called. Typically a method called in this way will either change the object or return a value. For instance, if s is a variable con-
15
Tutorial
taining a score, then
s.CreateInstrument("Flute")
adds a flute (changing the score), but
s.NthStaff(1)
returns
a value, namely an object containing the first staff.
Let’s look at the new code in detail. There is a pre-defined variable called Sibelius, which contains an object representing the Sibelius program itself. We’ve already seen the method
Sibelius.MessageBox()
. The method call
Sibelius.New()
tells
Sibelius to create a new score. Now we want to do something to this score, so we have to put it in a variable.
Fortunately, when you create a new score it becomes active (i.e. its title bar highlights and any other scores become inactive), so we can just ask Sibelius for the active score and put it in a variable:
newscore = Sibelius.ActiveScore.
Then we can tell the score to create a Piano: newscore.CreateInstrument("Piano"). But to add some text to the score you have to understand how the layout is represented.
16

Representation of a score

Representation of a score
A score is treated as a hierarchy: each score contains 0 or more staves; each staff contains bars (though every staff contains the same number of bars); and each bar contains “bar objects.” Clefs, text and chords are all different types of bar objects.
So to add a bar object (i.e. an object which belongs to a bar), such as some text, to a score: first you have to get which staff you want (and put it in a variable): (and put it in a variable):
bar.AddText(0,text,"Technique")
staff = newscore.NthStaff(1)
bar = staff.NthBar(1)
. You have to give the name (or index number – see
the text style to use (and it has to be a staff text style, because we’re adding the text to a staff).
Notice that bars and staves are numbered from 1 upwards; in the case of bars, this is irrespective of any bar number changes that are in the score, so the numbering is always unambiguous. In the case of staves, the top staff is no.1, and all staves are counted, even if they’re hidden. Thus a particular staff has the same number wherever it appears in the score.
; then you have to get which bar in that staff you want
; finally you tell the bar to add the text:
Text styl e s
on page 141) of
The
AddText
method for bars is documented later, but the first parameter it takes is a rhythmic position in the bar. Each note in
a bar has a rhythmic position that indicates where it is (at the start, one quarter after the start, etc.), but the same is true for all other objects in bars. This shows where the object is attached to, which in the case of Technique text is also where the left hand side of the text goes. Thus to put our text at the start of the bar, we used the value 0. To put the text a quarter note after the start of the bar, use 256 (the units are 1024th notes, so a quarter is 256 units – but don’t think about this too hard):
bar.AddText(256,text,"Technique");
To avoid having to use obscure numbers like 256 in your program, there are predefined variables representing different note values (which are listed later), so you could write:
bar.AddText(Quarter,text,"Technique");
or to be quaint you could use the British equivalent:
bar.AddText(Crotchet,text,"Technique");
For a dotted quarter, instead of using 384 you can use another predefined variable:
bar.AddText(DottedQuarter,text,"Technique");
or add two variables:
bar.AddText(Quarter+Eighth,text,"Technique");
This is much clearer than using numbers.

The system staff

As you know from using Sibelius, some objects don’t apply to a single staff but to all staves. These include titles, tempo text, rehearsal marks and special barlines; you can tell they apply to all staves because (for instance) they get shown in all the instrumental parts.
All these objects are actually stored in a hidden staff, called the system staff. You can think of it as an invisible staff which is always above the other staves in a system. The system staff is divided into bars in the same way as the normal staves. So to add the title “Potato” to our score we’d need the following code in our plug-in:
sys = newscore.SystemStaff; // system staff is a variable bar = sys.NthBar(1); bar.AddText(0,"POTATO SONG","Subtitle");
As you can see,
SystemStaff
is a variable you can get directly from the score. Remember that you have to use a system text style (here I’ve used Subtitle) when putting text in a bar in the system staff. A staff text style like Technique won’t work. Also, you have to specify a bar and position in the bar; this may seem slightly superfluous for text centered on the page as titles are (though in reality even this kind of page-aligned text is always attached to a bar), but for Tempo and Metronome mark text they are obviously required.
17
Tutorial

Representation of notes, rests, chords and other musical items

Sibelius represents rests, notes and chords in a consistent way. A rest has no noteheads, a note has 1 notehead and a chord has 2 or more noteheads. This introduces an extra hierarchy: most of the squiggles you see in a score are actually a special type of bar object that can contain even smaller things (namely, noteheads). There’s no overall name for something which can be a rest, note or chord, so we’ve invented the pretty name NoteRest. A NoteRest with 0, 1 or 2 noteheads is what you normally call a rest, a note or a chord, respectively.
If n is a variable containing a NoteRest, there is a variable
n.Duration
highest and lowest notes (assuming about the lowest note, such as methods and variables may be found in the
which is the note-value in 1/256ths of a quarter. You can also get
n.NoteCount
lownote.Pitch
Reference
isn’t 0). If you set
(a number) and
section below.
n.NoteCount
lownote = n.Lowest
lownote.Name
which contains the number of notes, and
n.Highest
and
n.Lowest
which contain the
, you can then find out things
(a string). Complete details about all these
Other musical objects, such as clefs, lines, lyrics and key signatures have corresponding objects in ManuScript, which again have various variables and methods available. For example, if you have a Line variable
, then
ln.EndPosition
gives the
ln
rhythmic position at which the line ends.
18

The “for each” loop

The “for each” loop
It’s a common requirement for a loop to do some operation to every staff in a score, or every bar in a staff, or every BarObject in a bar, or every note in a NoteRest. There are other more complex requirements which are still common, such as doing an operation to every BarObject in a score in chronological order, or to every BarObject in a multiple selection. ManuScript has a loop that can achieve each of these in a single statement.
for each
The simplest form of
thisscore = Sibelius.ActiveScore; for each s in thisscore // sets s to each staff in turn {
// ...do something with s
}
Here, since
thisscore
because staves are the type of object at the next hierarchical level of objects (see
for each
is like this:
is a variable containing a score, the variable s is set to be each staff in
Hierarchy of objects
thisscore
on page 42). For each
in turn. This is
staff in the score, the statements in {} braces are executed.
Score objects contain staves, as we have seen, but they can also contain a Selection object, e.g. if the user has selected a passage of music before running the plug-in. The Selection object is a special case: it is never returned by a only a single selection object; if you use the Selection object in a
for each
loop, by default it will return BarObjects (not Staves,
for each
loop, because there is
Bars or anything else!).
Let’s take another example, this time for notes in a NoteRest:
noterest = bar.NthBarObject(1); for each n in noterest // sets n to each note in turn {
Sibelius.MessageBox("Pitch is " & n.Name);
}
is set to each note of the chord in turn, and its note name is displayed. This works because Notes are the next object down the
n
hierarchy after NoteRests. If the NoteRest is, in fact, a rest (rather than a note or chord), the loop will never be executed – you don’t have to check this separately.
The same form of loop will get the bars from a staff or system staff, and the BarObjects from a bar. These loops are often nested, so you can, for instance, get several bars from several staves.
This first form of the second form of the
for each
for each
loop got a sequence of objects from an object in the next level of the hierarchy of objects. The
loop lets you skip levels of the hierarchy, by specifying what type of object you want to get. This
saves a lot of nested loops:
thisscore = Sibelius.ActiveScore; for each NoteRest n in thisscore {
n.AddNote(60); // add middle C
}
By specifying
NoteRest
after
for each
, Sibelius knows to produce each NoteRest in each bar in each staff in the score; otherwise it would just produce each staff in the score, because a Staff object is the type of object at the next hierarchical level of objects. The NoteRests are produced in a useful order, namely from the top to the bottom staff, then from left to right through the bars. This is chronological order. If you want a different order (say, all the NoteRests in the first bar in every staff, then all the NoteRests in the second bar in every staff, and so on) you’ll have to use nested loops.
So here’s some useful code that doubles every note in the score in octaves:
19
Tutorial
score = Sibelius.ActiveScore; for each NoteRest chord in score {
if(not(chord.NoteCount = 0)) // ignore rests {
note = chord.Highest; // add above the top note chord.AddNote(note.Pitch+12); // 12 is no. of half-steps (semitones)
}
}
It could easily be amended to double in octaves only in certain bars or staves, only if the notes have a certain pitch or duration, and so on.
This kind of loop is also very useful in conjunction with the user’s current selection. This selection can be obtained from a variable containing a Score object as follows:
selection = score.Selection;
We can then test whether it’s a passage selection, and if so we can look at (say) all the bars in the selection by means of a
loop:
each
if (selection.IsPassage) {
for each Bar b in selection {
// do something with this bar …
}
}
for
Be aware that you can not add or remove items from bars during iterating. The example of adding notes to chords above is fine because you are modifying an existing item (in this case a NoteRest), but it’s not safe to add or remove entire items, and if you try to do so, your plug-in will abort with an error. However, it’s very useful to add or remove items from bars, so you need to do that in
for
a separate
loop, after first collecting the items you want to operate on into a ManuScript array, something like this:
num = 0; for each obj in selection { if (IsObject(obj)) { n = "obj" & num; @n = obj; num = num + 1; } } selection.Clear(); for i = 0 to num { n = "obj" & i; obj = @n; // get an object from the pseudo array obj.Select(); }
The @n in this example is the array. To find out more about arrays, read on.
20

Indirection, sparse arrays and user properties

Indirection, sparse arrays and user properties

Indirection

If you put the @ character before a string variable name, then the value of the variable is used as the name of a variable or method. For instance:
var="Name"; x = @var; // sets x to the contents of the variable Name
mymethod="Show"; @mymethod(); // calls the method Show
This has many advanced uses, though if taken to excess it can cause the brain to hurt. For instance, you can use @ to simulate
name
“unlimited” arrays. If Thus:
i = 10; name = "x" & i; @name = 0;
is a variable containing the string
"x1"
, then
@name
is equivalent to using the variable x1 directly.
sets variable
x10
to 0. The last two lines are equivalent to
x[i] = 0;
in the C language. This has many uses; however, you’ll
also want to consider using the built-in arrays (and hash tables), which are documented below.

Sparse arrays

The method described above can be used to create “fake” arrays through indirection, though this is a little fiddly. ManuScript also provides Javascript-style sparse arrays, which can store anything that can be stored in a ManuScript variable, including references to objects. Like a variable, storing a reference to an object in a sparse array will preserve the lifetime of that object (because objects are reference counted), but the underlying object in Sibelius may become invalid if (say) a Score is modified.
To create a sparse array in ManuScript, use the built-in method empty array simply by passing in no variables to the
Sparse arrays provide a read/write variable called
CreateSpareArray
Length
CreateSparseArray(a1,a2,a3,
method.
that returns or sets the length of the array: when you set number greater than the present size of the array, the array is padded with null values; if you set than the present size of the array, any values beyond this number are removed.
To push one or more values to the end of the array, use the method
Pop()
of an array, use the method
.
Push(a1,
a2, ... an). To remove and return the last element
An example of how to use a sparse array:
array = CreateSparseArray(4,5,6); array[10] = 19; // creates 11th element of array, intervening elements are null array.Length = 20; // extends array to 20 elements, new elements are all null
Sparse arrays by their nature may not have values in every array element. To return a new sparse array containing only the populated indices of the original sparse array (i.e. those that are not null), use the array’s
ValidIndices
using the above sparse array:
a4...an). You can create an
Length
Length
to a number smaller
variable. For example,
to a
array2 = array.ValidIndices; // will contain values 0, 1, 2, 10 and 19 return array[array2[0]]; // returns the first populated element of array
You can compare two sparse arrays for equality, e.g.:
if (array = array2) {
// do something
}
To access the end of an array, it’s convenient to use negative indices; e.g.
array[-1]
returns the last element,
array[-2]
returns the penultimate element, and so on. It’s not possible to access elements before the start of the array, so if you do e.g.
array[-100]
on a six element array, you will get
array[0]
returned.
21
Tutorial
Some things to remember when using sparse arrays:
*
Sparse arrays use a zero-based index.
*
Elements that have not been initialised are null, and do not cause an error when referenced.
*
Assigning to an index beyond the current length increases the
*
If an array contains references to objects, whether the arrays are equal or not depends on the implementation of equality for
Length
to one greater than the index assigned to.
those objects.

User properties

All ManuScript objects other than those listed below, including objects created by Sibelius, can have user properties attached to them, allowing for convenient storage of extra data, encapsulation of several items of data within a single object, and returning more than one value from a method, among other things.
To create a new user property, use the following syntax:
._property:
object
property_name
=
value
;
where object is the name of the object, property_name is the desired user property name, and value is the value to be assigned to the new user property. User properties are read/write and can be accessed as object
.
property_name.
To get a sparse array containing the names of all the user properties belonging to an object, you can do e.g.:
names = object._propertyNames;
Here is an example of creating a user property:
nr = bar.NoteRest; nr._property:original = true; if (nr.original = true) {
// do something
}
Some things to remember when using user properties:
*
If you attempt to get or set a user property that has not yet been created, your plug-in will exit with a run-time error.
*
To check whether or not a user property has been created without causing a run-time error, use the notation
._property:
object
*
User properties cannot be created or accessed for normal data types (e.g. strings, integers, etc.), the global old-style ManuScript arrays created by
*
User properties that conflict with an existing property name cannot be accessed as be accessed using the
*
User properties belong to a particular ManuScript object and disappear when that object’s lifetime ends. To stop an object
property_name, which will be null if no matching user property has been created yet.
._property:
CreateArray()
notation).
, old-style hashes created by
object.
CreateHash()
property_name (though they can
Sibelius
, and null.
object,
dying, you can (for example) store it in a sparse array, but be aware that its contents may become invalid if (say) the underlying score changes.

Dictionary

Dictionary
construction. It also has methods allowing the use of aribtrarily named user properties, and can also have methods in plug-ins attached to it allowing the creation of encapsulated user objects (i.e. objects with variables and methods attached to them).
To create a dictionary, use the built-in function This creates a dictionary containing user properties called name1, name2, nameN with values value1, value2, valueN respectively.
A dictionary can contain named data items (like a can use strings to look items up within it.
The values in a dictionary can be accessed using square bracket notation, so you can use a dictionary like a hash table, e.g.:
22
is a programmer extensible object, simply allowing the use of user properties as above with convenient
CreateDictionary(
struct
test = CreateDictionary("fruit",apple,"vegetable",potato); test["fruit"] = banana; test["meat"] = lamb;
in languages like C++), or data that is indexed by string, so that you
name1, value1, name2, value2, ... nameN, valueN).
Indirection, sparse arrays and user properties
You can even put other objects, e.g. sparse arrays, inside dictionaries, e.g.
test2 = CreateDictionary("fruit", CreateSparseArray(apple,banana,orange));
You can access the user properties within a dictionary using the
return test2._property:fruit;
._property:
notation, e.g.:
which would return the array specified above. Even more direct, you can access user properties in a dictionary as if they were variables or methods, like this:
test2.fruit;
which would also return the array specified above. You can also return more than one value from any ManuScript method using a dictionary, e.g.:
getChord() value = CreateDictionary("a", aNote, "b", anotherNote); return value;
//... in another method somewhere chord = getChord(); trace(chord.a); trace(chord.b);
which returns two values, a and b, which you can access via e.g.
chord.a
and
chord.b
.
You can compare two dictionaries for equality, e.g.:
if (test2 = test3) { // do something }
Whether or not dictionaries containing objects evaluate as equal depends on the implementation of equality for those objects.
If you’re comfortable with programming in general, you may find it useful to be able to add methods to dictionaries, particularly if you are writing code designed to act as a library for other methods or plug-ins to call. Writing code in this way provides a degree of encapsulation and can make it easy for client code to use your library.
To add a method to a dictionary, call the dictionary’s
pluginmethod "(obj,x,y) { // a method that does something to obj }" test4 = CreateDictionary(); test4.SetMethod("doSomething",Self,"pluginmethod"); test4.doSomething(3,4); // call pluginmethod within the current plug-in, passing in // test4 (obj in the method above) and 3 (x in the method // above) and 4 (y in the method above)
In the example above, method is defined in the same plug-in, and
doSomething
is the name of the method belonging to the dictionary,
pluginmethod
SetMethod()
is the name of a method elsewhere in the plug-in (shown at the top
method, e.g.:
Self
tells the plug-in that the
of the example).
To return a sparse array containing the names of the methods belonging to a dictionary, use the dictionary’s
GetMethodNames() MethodExists()
method. You can also check the existence of a particular method using the dictionary’s
method. Use the dictionary’s
CallMethod()
method to call a specific method, where the name of the
method is the first parameter, and any parameters to be passed to the specified method follow. For example:
array = test4.GetMethodNames(); // create sparse array containing method names first_method_name = array[0]; // sets first_method_name to name of first method methodfound = test4.MethodExists("doSomething"); // returns True in this case; test4.CallMethod("doSomething",5,6);
Everything you put into a dictionary is a user property, so all of the methods outlined in data in dictionaries too.
User properties
above can be used on
23
Tutorial

Using user properties as global variables

You ca n s t o r e itself. In the example below, assigned to the plug-in, containing a Dictionary:
User properties assigned to the plug-in are persistent between invocations. Take care to ensure that these user properties are created before you attempt to use them, otherwise your plug-in will abort with a run-time error. Using the
_property:
if property_name hasn't been created yet.
SparseArray
Self._property:globalData = CreateDictionary(1,2,3,4); // globalData and Self.globalData can be used interchangeably trace(globalData); trace(Self.globalData);
and
Dictionary
Self
is the object that corresponds to the running plug-in, and a user property
objects, and indeed any other object, as user properties of the Plugin object
globalData
property_name syntax never causes run-time errors, but direct references to property_name force a runtime error
is
The example below shows how to test the existence of a specific user property,
globalCounter
, initialise it to 0 if it is not
found, then increment it by 1 every time the plug-in runs:
// Test the persistence of user properties if (Self._property:globalCounter = null) { Self._property:globalCounter = 0; } globalCounter = globalCounter + 1; // this number increases by one every time the plugin is run trace(globalCounter); trace(Self.globalCounter);
If you store a reference to a musical object in a user property that is assigned to the plug-in, there is an increased danger of that reference becoming invalid due to the score being closed or edited, etc. Use the
IsValid()
method to validate such data before
using it.
User properties of plug-ins will be inaccessible (except by using the
_property:
property_name syntax) if there is an existing
global variable of the same name.

Watch out for recursive cycles!

Be careful not to create recursive cycles using arrays, user properties and dictionaries. When you use, say, an array in a dictionary, you are not creating a copy of the array or its values, but a reference to the original array: dictionaries and arrays are objects, not values. As a result, you could write something where an array contains a dictionary that itself refers to the original array: this will lead to Sibelius crashing. So be careful!

Other things to look out for

The Parallel 5ths and 8ves plug-in illustrates having several methods in a plug-in, which we haven’t needed so far. The Proof-read plug-in illustrates that one plug-in can call another – it doesn’t do much itself except call the CheckPizzicato, CheckSuspectClefs, CheckRepeats and CheckHarpPedaling plug-ins. Thus you can build up meta-plug-ins that use
libraries of others. Cool!
(You object-oriented programmers should be informed that this works because, of course, each plug-in is an object with the same powers as the objects in a score, so each one can use the methods and variables of the others.)
24

Dialog editor

Radio button
Checkbox
Button
Static text
Editable text
Combo box
List box
Group box
Dialog editor
For more complicated plug-ins than the ones we’ve been looking at so far, it can be useful to prompt the user for various settings and options. This may be achieved by using ManuScript’s simple built-in dialog editor. Dialogs can be created in the same way as methods and data variables in the plug-in editor.

Showing a dialog in a plug-in

To show a dialog from a ManuScript method, we use the built-in call
Sibelius.ShowDialog(dialogName, Self);
where dialogName is the name of the dialog we wish to show, and
Self
is a “special” variable referring to this plug-in (telling
Sibelius to whom the dialog belongs). Control will only be returned to the method once the dialog has been closed by the user.

Creating or editing a dialog

To create a new dialog, choose the Dialog radio button at the bottom of the window that lists methods, data and dialogs, and click Add. To edit an existing dialog, select it from the Dialogs list box at the top right-hand corner of the window, and click Edit.
The dialog form will then appear, along with a long thin “palette” of available controls, as follows:
To create a new control, simply drag and drop it from the palette onto the dialog.

Dialog properties

With no controls selected, either double-click on a blank part of the dialog (or right-click, and then choose Properties) to access the dialog’s Properties dialog, which allows you to specify:
*
Name: the value of dialogName for the
Sibelius.ShowDialog()
method call (see
Showing a dialog in a plug-in
above).
*
Title: the name of the dialog as it appears in its title bar.
*
Size: the Width and Height (measured in somewhat arbitrary dialog units); you can also set the size of the dialog by resizing it directly when editing it.
*
Position: the X and Y position that the dialog should open at by default.

Laying out controls

The dialog editor includes a number of simple options for producing a pleasing layout:
*
To select a control, either click it or hit Tab to select the next control in the creation order (Shift-Tab selects the previous control).
*
To nudge a selected control, simply use the arrow keys.
*
To align controls, select them using Ctrl+click (Windows) or X-click (Mac), then use e.g. Ctrl+0 or X0 to align all of the
3
selected controls with the left-hand edge of the left-most control, or Ctrl+ top edge of the top-most control.
*
To space controls evenly, select them using Ctrl+click (Windows) or X-click (Mac), then use e.g. Ctrl+Shift+Alt+2 or
xzX2
most controls, or Ctrl+Shift+Alt+
to space the controls evenly in the distance between the top edge of the top-most and the bottom edge of the bottom-
0
or
xzX0
to space the controls evenly in the distance between the left-hand edge of the
or X3 to align all of the selected controls with the
25
Tutorial
left-most and the right-hand edge of the right-most controls. Once controls are spaced evenly, you can increase or decrease the space between them proportionally by typing Ctrl+Shift+Alt+
3/2/0/1
or
xzX3/2/0/1
as appropriate.
You can optionally display a grid to aid with alignment. Right-click on a blank part of the dialog and choose Grid from the context menu to see a dialog with settings for the grid:
Switch on Show grid to show the grid in the editor. Choose between Dots or Lines, and specify the Opacity of the grid display by adjusting the slider. Switch on Snap to grid to enable control snapping as you drag them with the mouse. Although a control that you nudge with the keyboard will not snap to the grid, one side of its selection outline will flash when it comes into alignment with the grid in either the horizontal or vertical directions.

Undo and redo

You can undo and redo everything you have done while editing a dialog using Ctrl+Z or XZ to undo and Ctrl+Y or XY to redo.

Testing your dialog

To test your dialog within the editor, right-click a blank part of the dialog and choose Test from the context menu (or type the
X
shortcut Ctrl+T or
T). To finish testing and return to the editor, simply hit Esc, or click any control whose properties are set to
close the dialog (e.g. an OK or Cancel button, if you have created one).

Saving your changes

To save the changes to your dialog, simply click the close button in the dialog’s title bar: if you have any unsaved changes, Sibelius will ask you whether or not to save the changes.

Set Creation Order

If you have done any programming in other languages that allow you to edit dialogs, you will probably be familiar with the concept of tab order, which refers to the order in which controls are given the focus when the user repeatedly hits the Tab key to cycle through them. ManuScript has a similar concept called creation order, so named because the order in which the controls in a dialog are created affects not only the tab order but also some other subtle things (including radio button grouping – see
buttons
To set the creation order of controls in your plug-in’s dialog, right-click on a blank part of the dialog and choose Set Creation Order from the context menu. A special display appears overlaid on the controls in your dialog, like this:
below).
Radio
To set the creation order, simply click on each control in order. If you make a mistake, hold down Ctrl or control whose order is correct to restart the sequence from that point, then release Ctrl or remaining controls. Once you’re done, hit Esc to finish editing the creation order.
26
X
and click on the last
X
and resume clicking on the

Control properties

Every control that you create also has a Properties dialog, which can be accessed by double-clicking a selected control (or by right-clicking and choosing Properties from the
X
context menu, or by typing the shortcut Ctrl+Return or radio button control, for example, is shown on the right.
With a control selected, the properties window varies depending on the type of the control, but most of the options are common to all controls, and these are as follows:
*
ID: an internal string that identifies the control; Sibelius generates this for you automatically, but you can change if you like
*
Tex t: the text appearing in the control
*
Position (X, Y): where the control appears in the dialog, in coordinates relative to the top left-hand corner
*
Size (width, height): the size of the control
*
Variable storing control’s value: the ManuScript Data variable that will corre- spond to the value of this control when the plug-in is run
*
Method called when clicked: the ManuScript method that should be called whenever the user clicks on this control (leave blank if you don’t need to know about users clicking on the control)
*
Click closes dialog: select this option if you want the dialog to be closed whenever the user clicks on this control. The addi- tional options Returning True / False specify the value that the the window is closed in this way.
*
Give this control focus: select this option if the “input focus” should be given to this control when the dialog is opened, i.e. if this should be the control to which the user’s keyboard applies when the dialog is opened. Mainly useful for editable text controls.
-Return). The dialog for a
Sibelius.ShowDialog
method should return when
Dialog editor
Other options vary according to the type of control selected.

Combo boxes and list boxes

Combo boxes and list boxes have an additional property; you can set a variable from which the control’s list of values should be taken. Like the value storing the control’s current value, this should be a global Data variable. However, in this instance they have a rather special format, to specify a list of strings rather than simply a single string. Look at the variable
_ComboItems
String Fingering for an example – it looks like this:
_ComboItems {
"1" "2" "3" "4" "1 and 3" "2 and 4"
}
List boxes have one further property, which is to determine whether they should allow a single selection or multiple selections. The return value from a combo box or a single-selection list box is a single string. If a list box is set to allow multiple selections, the selection is returned as an array of strings.

Radio buttons

Radio buttons also have an additional property that allows one to specify groups of radio buttons in plug-in dialogs. When the user clicks on a radio button in a group, only the other radio buttons belonging to that groups are deselected; any others in the dialog are left as they are. This is extremely useful for more complicated dialogs.
in Add
To specify a radio group, pick one control from each group that represents the first button of the group, and for these controls ensure that the checkbox Start a new radio group is selected in the control’s Properties dialog. Then set the creation order of the controls (see
Set Creation Order
above). A radio button group is defined as being all the radio buttons created between
27
Tutorial
two buttons that have the Start a new radio group flag set (or between one of these buttons and the end of the dialog). So to make the radio groups work properly, ensure that each group is created sequentially in order, with the button at the start of the group created first, and then all the rest of the radios in that group. To finish, click the Set Creation Order menu item again to deactivate this mode.

Static text

Static text controls additionally allow you to determine whether the text should be aligned to the Left (useful for explanatory text) or to the Right (useful for text associated with a specific control to its right, such as an edit control, checkbox or combo box).

Buttons

In most plug-in dialogs, you will want the OK button to be the default button for the dialog, such that if the user hits Return or Enter on their keyboard, the dialog is confirmed, and closes. Likewise, you will want the Cancel button to respond to the user
hitting Esc on their keyboard, closing the dialog without making any changes.
For OK buttons, or other buttons that should confirm the dialog, switch on the Default button for dialog checkbox in the button’s Properties dialog. Each dialog should only have one default button. You will also normally set Click closes dialog,
returning to Tr ue. Depending on the other controls in your dialog, you may additionally want to check Give this control focus; if you have one or more edit controls in the dialog, you should probably set Give this control focus on the first of
those controls instead.
Cancel buttons, by contrast, should normally only have Click closes dialog, returning set to False.
28

Debugging your plug-ins

When developing any computer program, it’s all too easy to introduce minor (and not so minor!) mistakes, or bugs. ManuScript performs its own internal error checking at all times, and you’ll find that if you try to access a non-existent method or variable on an object, or make a syntax error, or attempt to add or remove bars or items from bars while iterating over them, the plug-in will throw an error and open the plug-in editor window at the line that generated the error.
As ManuScript is a simple, lightweight system, there is no special purpose debugger, but there are a handful of tools provided to help you debug your plug-ins.

Undo

One good technique for finding problems in your plug-ins is to set Sibelius’s undo buffer to a very small size, or to disable it altogether (by dragging the slider on the Other page of File ManuScript does not throw an error when you perform an illegal operation (e.g. adding or deleting an object while iterating over a bar), reducing the undo buffer to its smallest possible size will expose the problem right away – though be warned, the result of such a problem may well be that Sibelius will crash.

Plug-in Trace Window

The trace window can be shown by choosing Plug-ins> Plug-in Trace Window. A special ManuScript command,
trace(
particular points. These commands can then be removed when you’ve finished debugging. Another useful feature of the trace window is function call tracing. When this is turned on, the log will show which functions are being called by plug-ins.
string), will print the specified string in the trace window. This is useful to keep an eye on what your plug-in is doing at
>
Preferences to its leftmost position). In the unlikely event that
One potential pitfall with the
trace(
string) approach to debugging is that the built-in hash table and array objects discussed
earlier aren’t strings, and so can’t be output to the trace window. To avoid this problem, both of these objects have a corresponding method called
WriteToString()
, which returns a string representing the whole structure of the array or hash at that point. So
we could trace the current value of an array variable as follows:
trace("array variable = " & array.WriteToString());

Checking the validity of objects

One of the common problems that you might encounter when writing complex plug-ins is that the object you are trying to operate on is no longer valid (e.g. it has already been deleted). You can enable error checking – either for all objects, or for individual objects – that will cause your plug-in to throw an error if an object is no longer valid.
To enable error checking, use the ManuScript command
true
Boolean parameter enable to
. If enable is the only parameter, validation checking is enabled for all types of objects, and all
plug-ins. If you supply one or more object parameters (e.g.
ValidationChecking(
Tuplet, Score, BarObject
checked, and only in the currently running plug-in. You should ensure
ValidationChecking
enable[, object1[, object2]...]), and set the
, etc.), only those objects will be
is set to
false
before you give
your plug-ins to anybody else to use.
You can also use the special method question no longer exists.
GetValidationError(
error has occurred, so you can do e.g.
IsValid()
trace(GetValidationError(score));
to determine whether an object is valid: it will return
false
if the object in
object) returns an empty string if there is no error, or returns a string if an
to trace any validation error returned by a
Score object to the trace window.

Stopping the plug-in

If you want to force your plug-in to stop on a particular error condition, use the method stop your plug-in, display the optional message in an alert box, and open the plug-in editor at the line of code reached.
StopPlugin(
[message]), which will
You ca n als o u se
ExitPlugin()
, which exits the plug-in cleanly without dropping into the plug-in editor.
Tutorial

Storing and retrieving preferences

In Sibelius 4 or later, you can use Preferences.plg, contributed by Hans-Christoph Wirth, to store and retrieve user-set preferences for your plug-ins.

How does it work?

Preferences.plg stores its data in a text file in the user’s application data folder. Strings are accessed as associated pairs of a key (the name of the string) and a value (the contents of the string). The value can also be an array of strings, if required.

Initializing the database

errorcode = Open(
Open the library and lock for exclusive access by the calling plug-in. The calling plug-in is identified with the string plugin­name. It is recommended that this string equals the unique Sibelius menu name of the calling plug-in.
Parameter featureset is the version of the feature set requested by the calling plug-in. The version of the feature set is currently
020000. Each library release shows in its initial dialog a list of supported feature sets. The call to a user message if you request an unsupported feature set. If you should want to prevent this user information (and probably setup your own information dialog), use
After
Open()
pluginname,featureset
);
CheckFeatureSet()
Open()
first.
the scope is undefined, such that you can access only global variables until the first call to
will fail and show
SwitchScope()
.
Return value:
Open()
returns zero or a positive value on success. A negative result indicates that there was a fatal error and
the database has not been opened.
*
-2 other error
*
-1 library does not support requested feature set
*
0 no common preferences database found
*
1 no preferences found for current plug-in
*
2 preferences for current plug-in loaded
In case of errors (e.g. if the database file is unreadable),
Open()
offers the user an option to recover from the error condition.
Only if this fails too will an error code be returned to the calling plug-in.
errorcode = CheckFeatureSet(
featureset
);
Check silently if the library supports the requested feature set.
Return value:
CheckFeatureSet()
returns zero or a positive value on success. A negative value indicates that the
requested feature set is not supported by this version.
errorcode = Close();
Release the exclusive access lock to the library. If there were any changes since the last call to data changes back to disk (probably creating a new score, if there was none present).
Return value:
Close()
returns zero or a positive value on success. A negative result indicates that there was a fatal error and
the database has not been written.
Open()
or
Write()
, dump the
errorcode = CloseWithoutWrite();
Release the exclusive access lock to the library, discarding any changes performed since last call to
Return value:
CloseWithoutWrite()
returns zero or a positive value on success. A negative result indicates that there
Open()
or
Write()
was a fatal error, namely that the database was not open at the moment.
errorcode = Write(
dirty
);
Force writing the data back to disk immediately. Keep library locked and open. If dirty equals 0, the write only takes place if the data has been changed. If dirty is positive, the common preferences score is unconditionally forced to be rewritten from scratch.
Return value:
Write()
returns zero or a positive value on success. A negative result indicates that there was a fatal error and the
database has not been written.
30
.
Loading...
+ 135 hidden pages