This page is for developers of Bol Processor BP3 (read installation). It is not a formal description of algorithms carried by the console’s C code, but rather an illustration of their management of musical processes that may be helpful for checking or extending algorithms.

All examples are contained in file “-da.checkPoly” of the “ctests” folder in the distribution.

## Syntax of silences

In Bol Processor data/grammar syntax, silences (*rests* in conventional music terminology) are represented either with an hyphen ‘**-**’ for one-unit duration, or integer ratios to specify a more complex duration:

- “4″ is a rest of 4-unit duration
- “5/3″ is a rest of (approximately) 1.666-unit duration
- “3 1/2″ is a rest of 3.5-unit duration

For instance, “C4 C5 3/2 D5 E5″ yields the following piano roll with a rest of 3/2 (1.5) units starting on beat 2 and ending on beat 3.5:

In this tutorial we use the default metronome value = 60 beats per minute.

Another simple example is {3 1/2, C3 D3 B2} which is the sequence of notes “C3 D3 B2″ constrained to total duration 3 1/2 (3.5) beats. This silence is the first field of the *polymetric expression* (explained below). This yields the following piano roll:

or equivalently the sound-object graph:

## Syntax of tempo

Any sequence of symbols compliant with Bol Processor syntax is processed as a **polymetric expression**. Typical forms are:

- field 1, field2 indicating that field1 and field2 should be superposed and the total duration should be that of field1;
- field1.field2 indicating that field1 and field2 should be in sequence where the duration of each field should be that of field1;
- {expression} is equivalent to expression.

Brackets ‘{‘ and ’}’ are used to produce multilevel expressions.

A set of examples of polymetric expressions may be found on tutorial Polymetric structures.

For instance, {{C4 D4, E4 F4 G4}, E5} yields the following structure:

To interpret this structure, the Bol Processor needs to insert explicit tempo values into the expression. Precisely, in this case, the most compact representation with explicit tempo values would be:

*1/1 {{C4 D4,*2/3 E4 F4 G4} ‚*2/1 E5}

Expressions such as “*2/3″ indicate that the duration of each note (or sound-object) should be multiplied by 2/3 irrespective of preceding statements. This means that the durations of notes “E4”, “F4” and “G4” should be 2/3 seconds as shown on the graph.

Creating the compact representation with its explicit tempo markers may require recursive calls of a sophisticated procedure named *PolyExpand()* in file “Polymetric.c”.

At this stage it is important not to confuse notations:

- “2/3″ is a silence of duration 2/3 beats;
- “_tempo(2/3)” multiplies the current tempo by 2/3. This is a
*relative*tempo marker; - “*2/3″ sets the current durations of units to 2/3 of the metronome period. This is an
*absolute*tempo marker. Equivalently, “*4″ multiplies durations by 4, and “*1/5″ or “/5″ divides them by 5 — whereas “1/5″ is a silence lasting 1/5 beat.

The third syntax is the one used by Bol Processor’s time-setting algorithms. Despite its syntactically validity, we do not recommend using it in grammars and data because it may create conflicting durations in polymetric structures. For example, {*2/1 A4 B4, *3/1 A5 B5} does not make sense because it attempts to force the first field to duration 2 x 2 = 4 beats and the second field to 3 x 2 = 6 beats. The proper (never conflicting) manner of changing a tempo in data or grammars is the “_tempo(x)” performance tool.

## Expanding a polymetric expression

In the preceding paragraph, we saw {{C4 D4, E4 F4 G4}, E5} represented internally as *1/1 {{C4 D4,*2/3 E4 F4 G4} ‚*2/1 E5}. This internal representation is the most compact one containing explicit tempo markers. Therefore it the one maintained along all steps of time-setting.

Humans may prefer to see a more comprehensive representation called the **expanded polymetric expression**:

/3 {{C4_ _ D4_ _, E4_ F4_ G4_} , E5_ _ _ _ _}

This is obtained clicking the **EXPAND** button on a Data page. Underline symbols ‘_’ represent extensions of the duration of the preceding unit. These should not be confused with ‘-’ (silences). To make things clear, let us replace a ‘_’ with ‘-’:

/3 {{C4_ _ D4_ _, E4_ F4 **-** G4_}, E5_ _ _ _ _}

This yields the following structure in which “F4” is not extended:

The expanded polymetric expression may grow larger than comprehensive to a human observer. In this case, only the compact version is returned.

In Bol Processor console’s code, sound-objects (of all kinds) are identified by numbers. The variable used to designate them in algorithms is always *‘k’* or *‘kobj’*. There is an option to display object identifiers on a graph which is set by constant SHOWEVERYTHING. If set to true, the preceding sound-object graph would be:

Notes “C4”, “D4” etc. bear identifiers *kobj* = 2, 3 etc. Identifier “0” is reserved for extensions ‘_’ and “1” for silences “-”, none of which is shown on the graph. An exception is object #8 labelled «-» which is an out-time (null-duration) “silence” marking the end of the structure to facilitate its synchronization with the next item.

## The phase diagram

Given a compact polymetric structure, time-setting algorithms require a table in which every column is assigned a date (in physical time). Cells of this **phase diagram** contain the identifiers of sound-objects, including “0” and “1”. It is created by procedure *FillPhaseDiagram()* in file “FillPhaseDiagram.c”.

It is easy to guess that the table would grow very large if compression procedures were not applied. For instance, Listz’s *14 ^{th} Rhapsody* would require no less than 9 x 10

^{21}cells! The reason is that Bol Processor computes symbolic durations as integer ratios. A symbolic duration of 5/3 will never be replaced with “1.666” for two reasons: (1) roundings would cumulate as noticeable errors, and (2) we don’t know in advance how many decimals need to be kept. The physical duration of 5/3 beats depends on the metronome and the succession of “_tempo(x)” controls modifying the tempo.

Let us first examine a non-problematic case. The polymetric expression /3 {{C4_ _ D4_ _, E4_ F4 **-** G4_}, E5_ _ _ _ _} creates the following phase diagram:

In this example, if the metronome is set to 60 beats per minute the physical duration assigned to each column is 1/3 second = 333 ms. When the diagram grows larger, this physical duration may decrease beyond limit. This is where **quantization** is invoked. It is set to 10 milliseconds by default, which means that two events occurring within than 10 ms may be written into the same column. To this effect, the compact polymetric structure is rewritten using a **compression rate** (Kpress) that makes it fit a phase diagram of suitable size.

If the musical piece lasts for 10 minutes we’ll still get 10 x 60000 / 10 = 60000 columns in the table. Filling the phase diagram requires a very high compression rate, for instance more than 5 x 10^{12} for Beethoven’s *Fugue in B-flat major*.

Adding to the difficulty, the algorithm must take care of sequences of events falling into the same column. This situation is signaled by variable *toofast* obtained by comparing the current tempo with the maximum tempo accepted in the structure. In the *toofast* case, each event is written on a new line of the table in such a way that the sequential order of the stream will be respected.

Thus, we end up with 12132 lines for the phase table of Beethoven’s *Fugue*, in which the longest *toofast* stream contains 625 events — notes or sound-objects. These 625 events performed within a single frame of 10 ms actually include events ‘_’, namely extensions of notes belonging to the stream.

## Dealing with complex ratios

In Bol Processor terminology, an integer ratio p/q is “complex” when either ‘p’ or ‘q’ goes beyond a limit which depends on the source code. The limit is ULONG_MAX, the maximum value of an *unsigned long* type, currently 18446744073709551616.

In Bol Processor’s console code, ‘p’ and ‘q’ are actually encoded as *double* floating-point numbers whose mantissa may contain as many digits as *unsigned long* integers. Arithmetic operations are performed on fractions. Each resulting fraction is checked for complexity by a procedure named *Simplify()* in file “Arithmetic.c”:

- While ‘p’ or ‘q’ is greater than ULONG_MAX, divide ‘p’ and ‘q’ by 10;
- Divide ‘p’ and ‘q’ by their greatest common divider (GCD).

Part (1) of the *Simplify()* procedure generates rounding errors, yet these represent a few units of very large numbers. In this way, the accuracy of symbolic durations is maintained throughout the computation of complicated polymetric structures.

## Complex ratios in silences

Let us check the effect on quantization by playing:

C4 C5 36001/24000 D5 E5

Ratio 36001/24000 cannot be simplified. Nonetheless, 1/24000 beat would last 0.04 ms which is much less than the 10 ms quantization. Therefore, the ratio can be approximated to 36000/24000 and simplified to 3/2. The final result is therefore “C4 C5 3/2 D5 E5″:

Let us now consider “C4 C5 35542/24783 D5 E5″ which looks similar given that 35542/24783 (1.43) is close to 1.5. However, the computation is more complex… Using the 10 ms quantization, the ratio is reduced to 143/100 and the compact polymetric expression is:

/1 C4 C5 /100 - _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ /1 D5 E5

The 143/100 silence is now represented as a unique ‘**-**’ (*kobj* = 1) followed by 142 ‘**_**’ (*kobj* = 0). This sequence is *toofast* because *tempomax*, the maximum tempo accepted here, would be ‘50’ instead of ‘100’. The compression rate is *Kpress* = 2. *A complete explanation requires the polymetric algorithm exposed here.*

The process of filling the phase table is found in “FillPhaseDiagram.c”. We call ‘*ip*’ the index of the column into which the next event will be plotted. In the most common situation, for instance writing “C4 _ _” (object #2), two procedures are invoked:

**Plot()**writes ‘2’ (*kobj*) into column*ip***PutZeros()**writes two zeros into columns*ip + 1*and*ip +2*.

Thus “C4 _ _” will have a symbolic duration of 3 units, as expected.

The case is different with a silence lasting 143/100 because the *toofast* situation imposes that less than 142 ‘**_**’ should be inserted after ‘**-**’. To this effect, a (floating-point) variable *part_of_ip* is initialized to 0 and gets incremented by a certain value until it reaches beyond *Kpress*. Then *Plot()* and *PutZeros() *are called, *part_of_ip* is reset and a new cycle starts… until all 142 ‘**_**’ of the compact polymetric expression have been read.

The increment of *part_of_ip* in each cycle is:

part_of_ip += Kpress * tempomax / tempo;

In this simple example, *tempo* = 100, *tempomax* = 50 and *Kpress* =2. Therefore the increment is 1 and *part_of_ip* will reach the value of *Kpress* after 2 cycles. This amounts to saying that one in two ‘_’ will be skipped.

Incrementing *ip* requires a more complicated process. The algorithm keeps track of column numbers in the table as it would be created with *Kpress* = 1. These numbers are generally much larger than the ones of the actual phase diagram. The large number *i* is mapped to *ip* via the *Class()* function:

`unsigned long Class(double i) {`

unsigned long result;

if(Kpress < 2.) return((unsigned long)i);

result = 1L + ((unsigned long)(floor(i) / Kpress));

return(result);

}

Thus, each cycle of reading ‘**_**’ in the *toofast* situation ends up incrementing *i* and then updating *ip* via the *Class(i)* function. The increment of *i* is:

prodtempo - 1

in which:

prodtempo = Prod / tempo

Variables *Prod* and *Kpress* are calculated after creating the compact polymetric expression. *Prod* is the lowest common multiple (LCM) of all values of tempo, i.e. ‘100’ in this example.

Let us use integers *Pclock* and *Qclock* to define the metronome value as *Qclock* * 60 / *Pclock*. If the metronome is set to its default value of 60 bpm, then *Pclock* = *Qclock* = 1.

The following (simplified) code calculates *Kpress* and updates *Prod* accordingly:

`Kpress = 1. + (Quantization * Qclock * Prod) / Pclock / 1000.;`

if(Kpress > 1.) {

s = LCM(Prod, Kpress) / Prod;

if(s > 1. && s < 10. && Prod < 1000000.) Prod = Round(s * Prod);

s = Round(Prod / Kpress);

if(s > 10.) Prod = Kpress * s;

}

As expected we get the following sound-object graph:

## A more complex structure

This is a phrase of Liszt’s *14 ^{th} Hungarian Rhapsody*:

_tempo(80/39) {F1, C2} {2, F2} 667/480 {53/480, G1, G2} {1/2, Ab1, Ab2} {1/2, B1, B2}

The compact polymetric expression — with a few redundant ratios deleted — is:

*39/80 {F1, C2} {F2 _} *13/12800* -* _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ *689/12800 {G1

*,*G2} *39/160 {Ab1, Ab2} {B1

*,*B2}

yielding the following sound-object graph:

Let us calculate the duration of the silence between “F2” and “G1” in two ways:

- In the source polymetric expression, this silence is notated 667/480. Since the tempo is 80/39, its duration should be 667/480 * 39/80 = 0.67 beats (confirmed by the graph).
- In the compact polymetric expression, we find one ‘
**-**’ object followed by 666 ‘**_**’ prolongations at speed *13/12800. The duration is therefore 667 * 13/12800 = 0.67 beats.

Following the algorithm step by step would be tricky because *Prod* = 2496100 , *Kpress* = 24961 and *tempomax* = *Prod* / *Kpress* = 100. Within the silence, *tempo* = 985 and the increment of *part_of_ip* is 24961 * 100 / 985 = 2 534.11167… The number of cycles before *part_of_ip* reaches the value of *Kpress* is ceil(9.85) = 10. This means that 9 in 10 objects ‘**_**’ have been skipped.

## Conclusion

These examples and explanations provide insights for an easier comprehension of code in file “FillPhaseDiagram.c” of the console’s code. We hope that it will serve for future development or migration of algorithms.

This is also a demo of the complexity of time calculations when dealing with polymetric structures able to carry all details of real musical works — read Importing MusicXML scores for “real life” examples.