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:

in SHOWEVERYTHING mode
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 14th Rhapsody would require no less than 9 x 1021 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:

/3 {{C4_ _ D4_ _, E4_ F4 - G4_}, E5_ _ _ _ _}
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 1012 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:

The silence duration is 35542/24783 = 1.43 beats.
A more complex structure
This is a phrase of Liszt’s 14th 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:

Metronome is set to 60 beats per minute.
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.