User Tools

Site Tools


composingintroduction

Introduction to composing with dfscore

dfscore is set up to facilitate an extensible way to create compositions written using javascript - with help from abstractions and a framework.

Package structure

dfscore compositions are created and stored as packages, defined as:

  • a directory/folder with any valid name
  • containing at least one file named composition.xml

A package can also contain any resources the composer wishes to use in the composition - such as images for graphical scores and additional data files.

composition.xml structure

As mentioned above, the central requirement for a composition to exist is composition.xml . This is very simple XML container for the composition data, meaning that all instructions for dfscore to interpret are contained within dfscore tags:

<dfscore>
   ....
</dfscore>

Introduction tutorial

Performance

The first instruction required in a dfscore composition is the new Performance directive.

new Performance({title: "Hello World", composer: "dfScore"});

This 'constructor' has two sets of brackets - ( and { , which allow for multiple named parameters. These are detailed in the API reference but allow the adjustment of things such as tempo and the preview of forthcoming events.

Roles

After the performance has been created, the next instructions should be role definitions. At least one is required - here are two created with the names by which they will be referred to.

new Role("Lead"); 
new Role("Rhythm", {maxPerformers: 3});

Like the performance constructor, new Roles can have additional parameters inside {curly brackets}, detailed in the API reference. Here, the Rhythm role is allowed to have three individual people/performers associated with it (the default is one).

Events and performance

In dfscore an Event can be thought of as a page/pane or view. The composer can include text instructions with TextEvent, formatted or arbitrary HTML with HtmlEvent, Vextab markup notation displays with ScoreEvent, static images/graphics with ImageEvent and client-side scripted events with arbitrary functionality using ScriptEvent. These different types are detailed in the API reference.

Events are performed by using the perform() directive, referencing the role, event and duration (in milliseconds) to display the event for. The event referenced can be created before the perform directive or within it.

Creating an event before the perform instruction will be useful if the composer intends to re-use the event or display it to multiple performers:

new TextEvent("Hello World", "event1");
perform("Lead", "event1", 10000);
perform("Rhythm", "event1", 10000);

Here, there is one event created with the name event1 and then two instructions for the roles which have been set up. As the dfscore instructions are interpreted asynchronously per-role, this means that the Lead role and Rhythm role will perform event1 at the same time and hence will both display “Hello World” before looking for the next instruction.

Events can also be created in-line. This makes more sense if the event is not going to be re-used, and in this case it doesn't need a name to be supplied.

perform("Lead", new TextEvent("Hello Lead"), 7000);
perform("Rhythm", new TextEvent("Hello Rhythm"), 7000);

Here both roles will display different text for the same amount of time.

If the composer wants to issue the same event to all roles, like with event1 above, then there is a shortcut to instruct all roles in the performance to receive the message - by using roles without speechmarks.

perform(roles, new TextEvent("Hello everyone"), 6000);

This will result in all roles displaying “Hello everyone” for six seconds. Depending on the durations that have led to the current point, this may not necessarily mean that the event will be synchronised between roles. However in this case, as both of the roles, Lead and Rhythm have performed synchronised events (ie, 10s then 7s), the “Hello everyone” message will be synchronised.

Now another two events will be predefined (created before a perform() instruction, with a name). For these two, dfscore won't show the progress bar along the bottom of the screen, nor the preview of the next event (by default these are turned on). These parameters can be set using {curly bracket} parameters which you can find out more about in the Events section of the API reference.

new TextEvent("Hello brave new world", "brave1", { progressBar: false, showNextEvent: false});
new TextEvent("Hello brave old world", "brave2", { progressBar: false, showNextEvent: false});

Then the two roles can be instructed to perform these two in a way so that they will be out of sync with each other (note the durations given), but they will complete the given instructions at the same time - and therefore any instructions given after these will be synchronised again.
To demonstrate that the instructions can be laid out however the composer wishes, they are presented two to a line which could be easier to interpret in a large score/instruction set.

perform("Lead", "brave1", 6000); perform("Rhythm", "brave2", 4000);
perform("Lead", "brave2", 4000); perform("Rhythm", "brave1", 6000);

Following this, all roles perform one more event, created inline (anonymously):

perform(roles, new TextEvent("Goodbye world"), 6000);

And just to spice things up very slightly, here is dftool.rand() (a multi-usage random generator detailed on the API page), being used to determine whether the Lead role should have an additional event. With no parameters dftool.rand() returns a random true or false, so it can be used in a regular javascript evaluation like so:

if (dftool.rand()) perform("Lead", new TextEvent("The show is not over yet"), 7000);

Putting it together

That's a basic introduction to creating a simple dfscore composition just using text cues. Here's what it looks like with each of the bits detailed in the tutorial. In javascript, one way of using comments is by prepending text with (two slashes) which you can see in the assembly below.

<dfscore>
  //set up the performance

  new Performance({title: "Hello World", composer: "dfScore"});

  // define two roles
  new Role("Lead");                        // restricted to one person by default
  new Role("Rhythm", {maxPerformers: 3});  // allowed up to three people

  // pre-define a text cue
  new TextEvent("Hello World", "event1");

  // instruct both roles to perform the event defined above ("event1") for 10s
  perform("Lead", "event1", 10000);
  perform("Rhythm", "event1", 10000);

  // instruct both roles to perform different new in-line events for 7s
  perform("Lead", new TextEvent("Hello Lead"), 7000);
  perform("Rhythm", new TextEvent("Hello Rhythm"), 7000);

  // instruct all roles to perform the same new in-line event for 6s
  perform(roles, new TextEvent("Hello everyone"), 6000);

  // pre-define two events with the progress bar and event preview turned off
  new TextEvent("Hello brave new world", "brave1", { progressBar: false, showNextEvent: false});
  new TextEvent("Hello brave old world", "brave2", { progressBar: false, showNextEvent: false});

  // instruct both roles to perform the two events, but with different timings
  perform("Lead", "brave1", 6000);    perform("Rhythm", "brave2", 4000);
  perform("Lead", "brave2", 4000);    perform("Rhythm", "brave1", 6000);

  // instruct all roles to perform the same new in-line event for 6s
  perform(roles, new TextEvent("Goodbye world"), 6000);

  // depending on chance, the Lead event is instructed to perform a new in-line event for 7s
  if (dftool.rand()) perform("Lead", new TextEvent("The show is not over yet"), 7000);

  // performance concludes
  // if dftool.rand() is true, Lead will finish 7s after Rhythm.
  // if it is false, both roles will finish at the same time.

</dfscore>

Next steps

After you have had a look through the tutorial and understand the general layout / flow of dfscore instructions, take a look through the examples and don't hesitate to rearrange and test things out. You can implement logic and other directives/instructions in the dfscore composition using regular javascript. While you can get by with the examples/tutorial and without much reference to the language itself, it might be useful to check out some introductory guides. These may also help you to understand the API reference which details the dfscore objects/framework and can help you take advantage of more advanced functionality.

Be aware that many javascript guides/tutorials on the internet are geared towards web browsers - and while dfscore is presented in a browser, the code used in your dfscore instructions is actually interpreted on the server using node.js - but the logic and general concepts of functions/objects are the same. Here are some recommended pages.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Introduction (pay attention to 'server-side' references, and the 'what you should already know?' is also mostly irrelevant).

https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript

The limits

dfscore runs atop node.js - it is therefore possible to leverage any node.js functionality in compositions - that includes using additional libraries and modules.

At the moment some extreme things might break the server and you will have to stop/restart the node.js application (from your terminal interface). We'd be interested to hear about anything that goes wrong! Drop an email to q@1bpm.net if you think something is happening that you expect shouldn't be.

composingintroduction.txt · Last modified: 2015/06/23 18:31 (external edit)