B13) PolyMake

The algorithm at the heart of BP3

The hidden engine

When BP3 transforms {drums, bass, melody} into a temporal sequence where each voice is perfectly synchronized, one function does all the work: PolyMake(), in Polymetric.c. It has never been formally documented. Here is what we know.

Where does this article fit?

B5 explained what polymetry does in BP3. B12 showed how _tempo() and smooth time complicate duration calculations. Here, we dive into the how: the algorithm that, from a polymetric expression and temporal constraints, produces a sequence of events ordered in time.

 


The problem that PolyMake() solves

Consider a polymetric expression {v1, v2, ..., vk}. Each voice is a sequence of elements with durations (known or to be calculated). PolyMake() must produce a single sequence of timestamped events where:

  1. All voices have the same total duration (the duration is fixed by the first field — see B5)
  2. Each voice subdivides this duration according to the number and durations of its elements
  3. The temporal order within each voice is preserved
  4. Undetermined rests (...) receive a calculated duration to fill the remaining space
  5. _tempo() commands modify durations locally

It is a constraint-satisfaction problem: finding a temporal placement that simultaneously satisfies all these requirements.


The basic algorithm (without complications)

In the simplest case — no _tempo(), no ... — the expansion is direct.

Input: {do re mi, fa sol la si}

Step 1 — Calculate nominal durations:

  • Voice 1: 3 elements → each note lasts 1 symbolic unit
  • Voice 2: 4 elements → each note lasts 1 symbolic unit

Step 2 — Normalize:

  • The total duration is fixed by voice 1: 3 units
  • Voice 2 (4 elements, 4 nominal units) is compressed into 3 units → each note lasts 3/4

Step 3 — Calculate start times:

Event Voice Start time Duration
do 1 0 1
fa 2 0 3/4
sol 2 3/4 3/4
re 1 1 1
la 2 6/4 3/4
mi 1 2 1
si 2 9/4 3/4

Step 4 — Merge and sort: the events from both voices are merged into a single sequence sorted by start time.

Durations are rationals (Q) — no floats, no rounding (B12). This is what allows BP3 to handle ratios like 7 against 5 without accumulation errors.


Complication 1: undetermined rests

An undetermined rest (...) is a silence whose duration is not fixed in advance. PolyMake() calculates it so that the voice exactly fills the total duration.

Example: {do re ..., fa sol la si}

Voice 2 (4 elements) sets the total duration to 4 units. Voice 1 has 2 notes (2 units) + one .... The undetermined rest receives the remaining duration: 4 – 2 = 2 units.

When there are multiple ... in a voice, they receive equal durations. The system rejects zero durations — if the remaining space is zero, the rest is not placed.

Minimization (documented on bolprocessor.org) is the reverse process: replacing determined silences with ... when possible, to simplify notation. The minimization algorithm generates chains of equivalent rests, sorts them by frequency, and selects the solution with the maximum number of undetermined rests.


Complication 2: _tempo()

A _tempo(2) in a voice doubles the speed locally. This means that the actual duration of an element after the _tempo() is no longer its nominal duration — it is divided by the tempo factor.

The problem: the total duration of the voice is no longer simply the sum of nominal durations. One must traverse the voice while accounting for each tempo change to calculate the “actual” duration.

If two voices have different _tempo() settings, normalization becomes a system of equations — actual durations depend on the normalization factor, which depends on the actual durations.

Bernard Bel (Feb. 2026): “This implementation complicates the expansion algorithm a bit.”


Bel’s two algorithms (1992)

The paper “Two Algorithms” (Bel 1992, available on bolprocessor.org) formalizes the problem in two steps:

Algorithm 1 — Polymetric interpretation

Resolves incomplete polymetric expressions by assigning symbolic tempos. Transforms the notation into a sequence totally ordered in symbolic time.

Algorithm 2 — Time-setting

A constraint-satisfaction algorithm that calculates the precise physical times of each message. It takes into account:

  • The alignment of pivots (PivBeg, PivCent, etc.)
  • The truncation and elasticity of sound-objects
  • Relocatability
  • The metric and topological properties of prototypes

Complexity: $O(n_{\max}^2 \cdot i_{\max}^3)$ in the worst case, where $n_{\max}$ is the maximum number of objects and $i_{\max}$ is the maximum number of iterations of the backtracking algorithm.

This is the only place in BP3 where Bernard Bel used backtracking — a search technique that backtracks when a partial solution violates a constraint. The inspiration comes from Prolog.


PolyMake() as a scheduler

PolyMake() is, in effect, a constraint-based scheduler:

Scheduler concept PolyMake() equivalent
Agents Elements of each voice (notes, silences)
Resource The timeline
Constraints Durations, _tempo(), ..., synchronization between voices
Result Sequence of timestamped events

Unlike real-time schedulers (EDF, Rate Monotonic), PolyMake() is offline: it calculates everything before execution. The complete sequence is resolved in memory, then played.

Bernard Bel calls this process “time-setting” — the temporal placement of sound-objects under constraints. This is the central concept of his approach, which goes beyond the simple notion of a sequencer.


Key takeaways

  1. PolyMake() is the function in Polymetric.c that resolves polymetric expansion — the algorithmic heart of BP3
  2. Simple case: normalize voices to the same duration, merge → $O(n \log n)$
  3. Undetermined rests (...): duration calculated to fill the remaining space
  4. _tempo(): modifies durations locally → the normalization calculation becomes a system of equations
  5. Time-setting (Bel 1992): constraint-satisfaction with backtracking for sound-objects — $O(n^2 \cdot i^3)$
  6. The algorithm has never been formally documented — extraction and formalization remain an open task

Further reading

  • Bel, B. (1992): “Two algorithms for the instantiation of structures of musical objects” — the formalization of algorithms 1 (polymetric interpretation) and 2 (time-setting). PDF
  • Bel, B. (2001): “Rationalizing Musical Time” — why durations are in Q (rationals) and not floats.
  • bolprocessor.org: Polymetric structures — documentation of undetermined rests
  • bolprocessor.org: Minimising a polymetric structure — the minimization algorithm

Glossary

  • PolyMake() : C function in Polymetric.c that implements polymetric expansion. Not formally documented.
  • Polymetric expansion: Transformation of {v1, v2} into a sequence of timestamped events
  • Normalization: Adjustment of durations so that all voices have the same total duration
  • Undetermined rest: Silence ... whose duration is calculated by PolyMake()
  • Time-setting: Temporal placement of sound-objects under constraints (Bel 1992)
  • Constraint-satisfaction: Problem of finding values that satisfy a set of constraints
  • Backtracking: Algorithmic technique of backtracking when a partial solution fails
  • Sound-object: Musical entity with metric and topological properties, more general than a note

Links in the series

  • B5 — Polymetry and temporal structures — the what (PolyMake() is the how)
  • B12 — Smooth time and _tempo() — temporal complications
  • B9 — Time-objects — the entities that PolyMake() places in time
  • B11 — The AST — the Polymetric node that PolyMake() resolves

Prerequisites: B5, B12
Reading time: 14 min
Tags: #bp3 #polymake #polymetrie #algorithme #time-setting #constraint-satisfaction


Back to index