003, 192 Digital I/O, 192 I/O, 96 I/O, 96i I/O, Adrenaline,
AirSpeed, ALEX, Alienbrain, AME, AniMatte, Archive,
Archive II, Assistant Station, AudioPages, AudioStation,
AutoLoop, AutoSync, Avid, Avid Active, Avid Advanced
Response, Avid DNA, Avid DNxcel, Avid DNxHD, Avid DS
Assist Station, Avid Ignite, Avid Liquid, Avid Media Engine,
Avid Media Processor, Avid MEDIArray, Avid Mojo,
Avid Remote Response, Avid Unity, Avid Unity ISIS,
Avid VideoRAID, AvidRAID, AvidShare, AVIDstripe, AVX,
Beat Detective, Beauty Without The Bandwidth,
Beyond Reality, BF Essentials, Bomb Factory, Bruno, C|24,
CaptureManager, ChromaCurve, ChromaWheel,
Cineractive Engine, Cineractive Player, Cineractive Viewer,
Color Conductor, Command|8, Control|24, Cosmonaut Voice,
CountDown, d2, d3, DAE, D-Command, D-Control, Deko,
DekoCast, D-Fi, D-fx, Digi 002, Digi 003, DigiBase,
Digidesign, Digidesign Audio Engine, Digidesign
Development Partners, Digidesign Intelligent Noise
Reduction, Digidesign TDM Bus, DigiLink, DigiMeter,
DigiPanner, DigiProNet, DigiRack, DigiSerial, DigiSnake,
DigiSystem, Digital Choreography, Digital Nonlinear
Accelerator, DigiTest, DigiTranslator, DigiWear, DINR,
DNxchange, Do More, DPP-1, D-Show, DSP Manager,
DS-StorageCalc, DV Toolkit, DVD Complete, D-Verb, Eleven,
EM, Euphonix, EUCON, EveryPhase, Expander,
ExpertRender, Fairchild, FastBreak, Fast Track, Film Cutter,
FilmScribe, Flexevent, FluidMotion, Frame Chase, FXDeko,
HD Core, HD Process, HDpack, Home-to-Hollywood,
HyperSPACE, HyperSPACE HDCAM, iKnowledge, Impact,
Improv, iNEWS, iNEWS Assign, iNEWS ControlAir, InGame,
Instantwrite, Instinct, Intelligent Content Management,
Intelligent Digital Actor Technology, IntelliRender, Intelli-Sat,
Intelli-Sat Broadcasting Recording Manager, InterFX,
Interplay, inTONE, Intraframe, iS Expander, iS9, iS18, iS23,
iS36, ISIS, IsoSync, LaunchPad, LeaderPlus, LFX, Lightning,
Link & Sync, ListSync, LKT-200, Lo-Fi, MachineControl,
Magic Mask, Make Anything Hollywood,
make manage move|media, Marquee, MassivePack,
MassivePack Pro, Maxim, Mbox, Media Composer,
MediaFlow, MediaLog, MediaMix, Media Reader,
Media Recorder, MEDIArray, MediaServer, MediaShare,
MetaFuze, MetaSync, MIDI I/O, Mix Rack, Moviestar,
MultiShell, NaturalMatch, NewsCutter, NewsView,
NewsVision, Nitris, NL3D, NLP, NSDOS, NSWIN, OMF,
OMF Interchange, OMM, OnDVD, Open Media Framework,
Open Media Management, Painterly Effects, Palladiium,
Personal Q, PET, Podcast Factory, PowerSwap, PRE,
ProControl, ProEncode, Profiler, Pro Tools, Pro Tools|HD,
Pro Tools LE, Pro Tools M-Powered, Pro Transfer,
QuickPunch, QuietDrive, Realtime Motion Synthesis,
Recti-Fi, Reel Tape Delay, Reel Tape Flanger,
Reel Tape Saturation, Reprise, Res Rocket Surfer, Reso,
RetroLoop, Reverb One, ReVibe, Revolution, rS9, rS18,
RTAS, Salesview, Sci-Fi, Scorch, ScriptSync,
SecureProductionEnvironment, Shape-to-Shape,
ShuttleCase, Sibelius, SimulPlay, SimulRecord,
Slightly Rude Compressor, Smack!, Soft SampleCell,
Soft-Clip Limiter, SoundReplacer, SPACE, SPACEShift,
SpectraGraph, SpectraMatte, SteadyGlide, Streamfactory,
Streamgenie, StreamRAID, SubCap, Sundance,
Sundance Digital, SurroundScope, Symphony, SYNC HD,
SYNC I/O, Synchronic, SynchroScope, Syntax,
TDM FlexCable, TechFlix, Tel-Ray, Thunder, TimeLiner,
Titansync, Titan, TL Aggro, TL AutoPan, TL Drum Rehab,
TL Everyphase, TL Fauxlder, TL In Tune, TL MasterMeter,
TL Metro, TL Space, TL Utilities, tools for storytellers, Transit,
TransJammer, Trillium Lane Labs, TruTouch, UnityRAID,
Vari-Fi, Video the Web Way, VideoRAID, VideoSPACE,
VTEM, Work-N-Play, Xdeck, X-Form, and XMON are either
registered trademarks or trademarks of Avid Technology, Inc.
in the United States and/or other countries.
Bonjour, the Bonjour logo, and the Bonjour symbol are
trademarks of Apple Computer, Inc.
Thunderbolt and the Thunderbolt logo are trademarks of Intel
Corporation in the U.S. and/or other countries.
This product may be protected by one or more U.S. and nonU.S. patents. Details are available at www.avid.com/patents.
Product features, specifications, system requirements, and
availability are subject to change without notice.
Chapter 5. Global Constants .................................................. 156
Global Constants ..................................................... 156
Contentsv
Contentsvi
Chapter 1: Introduction
ManuScript is a simple, music-based programming language used to write plug-ins for Sibelius. ManuScript 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, visit the Simkin
website at www.simkin.co.uk.
Rationale
Providing a plug-in language for Sibelius addresses several different issues:
• Music notation is complex and infinitely extensible, so some users will sometimes want to add to a music notation program to expand its possibilities with these new extensions.
• It is useful to allow frequently repeated operations (for example, 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.
Chapter 1: Introduction1
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 – please contact us at www.sibelius.com/plugins 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.
System Requirements and Compatibility Information
Avid can only assure compatibility and provide support for hardware and software it has tested and approved.
For complete system requirements and a list of qualified computers, operating systems, hard drives, and thirdparty devices, visit: www.avid.com/compatibility.
Sibelius ManuScript Language Guide2
Conventions Used in Sibelius Documentation
Sibelius documentation uses the following conventions to indicate menu choices, keyboard commands, and
mouse commands:
:
ConventionAction
File > SaveChoose Save from the File tab
Control+NHold down the Control key and press the N key
Control-clickHold down the Control key and click the mouse but-
ton
Right-clickClick with the right mouse button
The names of Commands, Options, and Settings that appear on-screen are in a different font.
The following symbols are used to highlight important information:
User Tips are helpful hints for getting the most from your Sibelius system.
Important Notices include information that could affect data or the performance of your Sibelius
system.
Shortcuts show you useful keyboard or mouse shortcuts.
Cross References point to related sections in this guide and other Avid documentation.
Chapter 1: Introduction3
Sibelius ManuScript Language Guide4
Chapter 2: Sibelius ManuScript Language
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 (such as BASIC
or C), so you’re already familiar with ideas like variables, loops, and so on.
To create a new Sibelius plug-in:
1 Start Sibelius and open or create a new score.
2 Choose File > Plug-ins > Edit Plug-ins.
Chapter 2: Sibelius ManuScript Language Tutorial5
3 The following dialog appears:
4 Click New.
5 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.
Chapter 2: Sibelius ManuScript Language Tutorial6
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.
6 Type Test as the internal name, Test plug-in as the menu name and Tests as the category name, then click OK.
7 You’ll see Test (user copy) added to the list in the Edit Plug-ins dialog under a new Tests branch of the tree
view. Click Close. This shows the folder in which the plug-in is located (Tests, 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.
8 If you look in the Home > Plug-ins gallery again you’ll see a Tests category, with a Test plug-in underneath it.
9 Choose Home > Plug-ins > Tests > 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 bothered by this warning in future.) What does our new Test plug-in do? It just pops
up a dialog which says Test (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.
10 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 lis
showing the three types of information that can make up a plug-in:
• Methods: Methods are similar to procedures, functions, or routines in some other languages.
• Dialogs: The layout of any special dialogs you design for your plug-in.
• Data: Data are 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 “Edit Plug-ins” on page 5.
t and click Edit (or simply double-click the plug-in’s name to edit it). You’ll see a dialog
Chapter 2: Sibelius ManuScript Language Tutorial7
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 sometimes 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 main() in C/C++ and Java). In other
words, when you choose
other methods, you have to call them from the Run method—otherwise how can they ever do anything?
Home > Plug-ins > Tests > Test, the plug-in’s Run method is called. If you write any
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:
Chapter 2: Sibelius ManuScript Language Tutorial8
In the top field you can edit the name; in the next field you can edit the parameters (the 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 Test 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 is a string (that is, text) it is 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 can also use Ctrl+X/C/V or
(Windows) or Control-click (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);
X/C/V for cut, copy and paste respectively. If you right-click
You can check this makes sense (or, at least, some kind of sense) by clicking the
are any blatant mistakes (e.g. missing semicolons) you will be notified where they are.
Chapter 2: Sibelius ManuScript Language Tutorial9
Check Syntax button. If there
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 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
cannot use + as this works only for numbers (if you try it in the example above, you will get an interesting answer!).
One pitfall: try changing the second line to:
x += 1;
Then click
guages but not in ManuScript. You have to do x = x+1;.
Check syntax. You will encounter an error: this syntax (and the syntax x++) is allowed in various lan-
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 plugins to these locations 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 peruser 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\Plugins.
• On Mac, additional plug-ins are stored in subfolders at /Users/username/Library/Application
Support/Avid/Sibelius/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, such as Test.plg.
(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 // is ignored to the end of
the line. Anything 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
*/
Chapter 2: Sibelius ManuScript Language Tutorial10
For instance:
Sibelius.MessageBox("Hi!"); // print the active score
or:
Sibelius /* this contains the application */ .MessageBox("Hi!");
Variables
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 does not start with a digit.
A variable can contain an integer (whole number), a floating point number, a string (text) or an object (such as
a note)—more about objects in a moment. Unlike most languages, in ManuScript a variable can contain any type
of data—you do not 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 \ as an “escape character” to represent certain special things. To include a single quote character in your strings, use \', and to include a new line you should use \n. Because of this, to include the backslash itself in a ManuScript string one has to write \\.
Converting Between Numbers, Text, and Objects
Notice that the method MessageBox is expecting to be sent some text to display. If you give it a number instead
(as in the first call to MessageBox above) the number is converted to text. If you give it an object (such as a
score), no text is produced.
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’
Chapter 2: Sibelius ManuScript Language Tutorial11
Loops
“for” and “while”
ManuScript has a while loop which repeatedly executes a block of code until a certain expression becomes
True. Create a new plug-in called Potato. This is going to amuse one and all by writing the words of the wellknown 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)
{
text = x & " potato,";
Sibelius.MessageBox(text);
x = x+1;
}
Run it. It should display “1 potato,” “2 potato,” “3 potato,” “4 potato,” which is a start, though annoyingly you
have to click
The while statement is followed by a condition in ( ) parentheses, then a block of statements in { } braces
(you don’t need a semicolon after the final
some other languages, the braces are compulsory (you can’t omit them if they only contain one statement). Moreover, each block must contain at least one statement.
In this example you can see that we are testing the value of x at the start of the loop, and increasing the value at
the end. This common construct could be expressed more concisely in ManuScript by using a for loop. The
above example could also be written as follows:
OK after each message.
} brace). While the condition is true, the block is executed. Unlike
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.
Chapter 2: Sibelius ManuScript Language Tutorial12
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;
}
The rule for
if takes the form if (condition) {statements}. You can also optionally add else
{statements}, which is executed if the condition is false. As with while, 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.
Chapter 2: Sibelius ManuScript Language Tutorial13
Now let’s make this plug-in really cool. We can build up the four messages in a variable called text, and only display it at the end, saving valuable wear on your mouse button. We can also switch round the
to show off the use of not. Finally, we return to the
for syntax we looked at earlier.
if and else blocks
text = ""; // start with no text
for x = 1 to 5
{
if (not(x=4)) {
text = text & x & " potato, "; // add some text
} else {
text = text & x & "."; // add no. 4
}
}
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)
add
subtract
multiply
divide
remainder
negate
evaluate first
ManuScript evaluates operators strictly from left-to-right, unlike many other languages; so 2+3*4 evaluates
to 20, not 14 as you might expect. To get the answer 14, you’d have to write 2+(3*4).
ManuScript also supports floating point numbers, so whereas in some early versions 3/2 would work out as 1,
it now evaluates to 1.5. Conversion from floating point numbers to integers is achieved with the
RoundUp(
expr), RoundDown(expr), and Round(expr) functions, which can be applied to any expression.
Chapter 2: Sibelius ManuScript Language Tutorial14
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 =, < and >, 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, to be a chord in your score, and (say) add more notes to it:
thischord.AddNote(60); // adds middle C (note no. 60)
thischord.AddNote(64); // adds E (note no. 64)
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 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
Chapter 2: Sibelius ManuScript Language Tutorial15
This creates a score with a Piano, and types our potato text in bar 1 as Technique text.
The code uses the period (.) several times, always in the form variable.variable or
variable.method(). This shows that the variable before the period has to contain an object.
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 some languages). For instance, if n is a variable containing a note, then
n.Pitch is a num-
ber representing its MIDI pitch (60 for middle C), and n.Name is a string describing its pitch (“C4” for middle
C). The variables available for each type of 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 containing 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.
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.
To add a bar object (i.e. an object which belongs to a bar), such as some text, to a score:
1 Specify which staff you want (and put it in a variable): staff = newscore.NthStaff(1).
2 Specify which bar in that staff you want (and put it in a variable): bar = staff.NthBar(1); finally you
tell the bar to add the text: bar.AddText(0,text,"Technique").
3 Specify the name (or index number – see Text styles on page 141) of 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.
Chapter 2: Sibelius ManuScript Language Tutorial16
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.
Chapter 2: Sibelius ManuScript Language Tutorial17
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.NoteCount which contains the number of
notes, and n.Duration which is the note-value in 1/256ths of a quarter. You can also get n.Highest and
n.Lowest which contain the highest and lowest notes (assuming n.NoteCount isn’t 0). If you set
lownote = n.Lowest, you can then find out things about the lowest note, such as lownote.Pitch
(a number) and lownote.Name (a string). Complete details about all these methods and variables may be
found in Chapter 3, “Reference.”
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 ln, then
ln.EndPosition gives the rhythmic position at which the line ends.
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 Bar object 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 Bar object
in a multiple selection. ManuScript has a for each loop that can achieve each of these in a single statement.
The simplest form of for each is like this:
thisscore = Sibelius.ActiveScore;
for each s in thisscore // sets s to each staff in turn
{ // ...do something with s
}
Here, since thisscore is a variable containing a score, the variable s is set to be each staff in thisscore
in turn. This is because staves are the type of object at the next hierarchical level of objects (see “Hierarchy of
Objects” on page 47).
For each 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 for each loop, because there is only a single Selection object; if you use the Selection
object in a for each loop, by default it will return Bar objects (not Staves, Bars or anything else!).
Chapter 2: Sibelius ManuScript Language Tutorial18
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);
}
n 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 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 Bar objects from a bar. These loops
are often nested, so you can, for instance, get several bars from several staves.
This first form of the for each loop got a sequence of objects from an object in the next level of the hierarchy of
objects. The second form of the for each 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:
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.
Chapter 2: Sibelius ManuScript Language Tutorial19
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 for each loop:
if (selection.IsPassage)
{
for each Bar b in selection
{
// do something with this bar
…
}
}
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 a separate for 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.
Chapter 2: Sibelius ManuScript Language Tutorial20
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 “unlimited” arrays. If name is a variable containing the string "x1", then @name is equivalent to
using the variable x1 directly. Thus:
i = 10;
name = "x" & i;
@name = 0;
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 CreateSparseArray
You can create an empty array simply by passing in no variables to the CreateSpareArray method.
Sparse arrays provide a read/write variable called Length that returns or sets the length of the array: when you set
Length to a number greater than the present size of the array, the array is padded with null values; if you set
Length to a number smaller 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 Push
the last element of an array, use the method Pop().
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
Chapter 2: Sibelius ManuScript Language Tutorial21
(a1, a2, ... an). To remove and return
(a1,a2,a3,a4...an).
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 ValidIndi-
ces variable. For example, using the above sparse array:
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 ofthe array, so if you do e.g. array[-100] on a six element array, you will get array[0] returned.
Some things to remember when using sparse arrays:
• Sparse arrays use a zero-based index.
• Elements that have not been initialized are null, and do not cause an error when referenced.
• Assigning to an index beyond the current length increases the Length to one greater than the index assigned
to.
• If an array contains references to objects, whether the arrays are equal or not depends on the implementation of equality for 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:
object._property: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 ob-ject.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;
Chapter 2: Sibelius ManuScript Language Tutorial22
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 runtime error.
• To check whether or not a user property has been created without causing a run-time error, use the notation
object._property:
yet.
• User properties cannot be created or accessed for normal data types (e.g. strings, integers, etc.), the global
Sibeliusobject, old-style ManuScript arrays created by CreateArray(), old-style hashes created by
CreateHash(), and null.
• User properties that conflict with an existing property name cannot be accessed as object.
ty_name
• User properties belong to a particular ManuScript object and disappear when that object’s lifetime ends. To
stop an 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.
(though they can be accessed using the ._property: notation).
property_name, which will be null if no matching user property has been created
proper-
Dictionary
Dictionary is a programmer extensible object, simply allowing the use of user properties as above with convenient construction. It also has methods allowing the use of arbitrarily 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 CreateDictionary
nameN, valueN)
. This creates a dictionary containing user properties called name1, name2, nameN with values
(name1, value1, name2, value2, ...
value1, value2, valueN respectively.
A dictionary can contain named data items (like a struct in languages like C++), or data that is indexed by
string, so that you 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.:
test = CreateDictionary("fruit",apple,"vegetable",potato);
test["fruit"] = banana;
test["meat"] = lamb;
You can even put other objects, e.g. sparse arrays, inside dictionaries, e.g.
Chapter 2: Sibelius ManuScript Language Tutorial23
You can access the user properties within a dictionary using the ._property: notation, e.g.:
return test2._property:fruit;
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 SetMethod() method, e.g.:
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, doSomething is the name of the method belonging to the dictionary, Self tells the plugin that the method is defined in the same plug-in, and pluginmethod is the name of a method elsewhere in the
plug-in (shown at the top of the example).
Chapter 2: Sibelius ManuScript Language Tutorial24
Loading...
+ 180 hidden pages
You need points to download manuals.
1 point = 1 manual.
You can buy points or you can get point for every manual you upload.