OOLOI.ORG
Menu

OOLOI

An Organism Evolved.

OVERVIEW

DOCUMENTATION

NEWSLETTER

The Bazaar and the Cathedral

30/1/2026

0 Comments

 
Picture
​In a blog post from some time ago, Penitenziagite!, I wrote about linguistic impedance in software: the way systems shout incomprehensible demands at contributing developers, forcing them to think in the wrong language. That post was about architecture as translation – the scriptorium at the centre speaking Latin for precision, and the gate speaking the vernacular so people can actually participate.

This post is about governance.

Specifically: why Ooloi is open source, but not open in the way some people expect. And why it cannot be.

The Myth of the Open-Source Bazaar

​There is a persistent belief among developers that open source implies a particular governance model. In this vision, design is open, debate is open, architecture is open, decision-making is open, and even the rewriting of foundations is treated as normal community activity. The project becomes a bazaar: a bustling marketplace of patches and opinions, competing visions and negotiated direction.

This model works for some kinds of software. It fails for others. Music notation software belongs firmly in the latter category.

The problems Ooloi addresses – temporal coordination, concurrent structural mutation, global layout decisions, semantic correctness across voices – are not decomposable into independent opinions. They cannot be negotiated piecemeal. They require conceptual unity, which is another way of saying they require architectural closure.

A bazaar cannot produce that. However, a cathedral can.

What 'Closed' Means Here

Ooloi's core is closed – but not in the sense of secrecy. The code is MPL-2.0: inspectable, forkable, modifiable. What I mean by closed is something more precise: closed in the sense of authority over semantics.

The musical model is fixed. The invariants are fixed. The staged pipeline is fixed. The authority boundaries are fixed. This does not mean that development has stopped, or that new functionality will not appear. It means that the conceptual foundations are no longer under negotiation.

Closure is not Stagnation

​A closed semantic core is often misread as a claim of finality: finished, complete, unchangeable. That is not what I mean.

What is closed is the space of permissible reinterpretation. New features will arrive, new capabilities will arrive, refinements and extensions will arrive – but they must fit within the established model rather than redefine it.

This distinction matters because most architectural failure in open projects does not come from lack of innovation. It comes from uncontrolled semantic drift: the gradual erosion of guarantees as each contributor reinterprets the foundations to suit local convenience. Ooloi explicitly forbids that drift.

Why the Core must be Closed

​Ooloi's correctness depends on architectural decisions that only work as a coherent whole.

Immutability is treated as a semantic guarantee rather than a performance trick. STM is not merely one possible concurrency implementation among several; it is the concurrency model, because the alternatives import failure modes that Ooloi is explicitly designed to eliminate. Structural sharing is not optional; it is a prerequisite for the kind of scale where a full orchestral score can be edited in real time without the system grinding to a halt. Computation is staged because global layout decisions are otherwise intractable. Piece state is single-authority because reconciliation architectures – the kind where multiple sources of truth must be merged – create exactly the class of bugs that have plagued notation software for forty years.

These are not interchangeable components. They are constraints, and constraints that reinforce each other. You cannot selectively replace one of them. You cannot introduce mutability 'for performance'. You cannot swap out the concurrency model. You cannot dissolve authority boundaries. Each such change collapses guarantees that are only meaningful because the other constraints hold.

The cathedral stands because the architecture must stand.

Why This Enables Real Openness

​Here is the paradox: by closing the core, Ooloi makes everything around it genuinely open.

Because the centre does not move, APIs stop being provisional. Semantics do not drift. Performance characteristics remain predictable. Plugin contracts remain valid across versions, which means plugin authors can build with confidence rather than anxiety about the next breaking change.

Plugins become first-class citizens rather than tolerated afterthoughts. Any JVM language can participate without translation into a single house dialect. Boundaries stay explicit. Failure modes stay contained.

This is the same pattern that made TeX durable, SQLite coherent, and the JVM stable enough to host entire ecosystems. A fixed centre enables freedom at the edges.

The Cuckoo-Chick Problem

Visibility attracts contributors. Most are helpful; some are enthusiastic but misaligned; a few arrive with expectations the project cannot and will not meet.

I have learned to recognise two failure modes.

1: Misaligned help

These contributors mean well. They propose changes that would, in effect, produce a different system entirely.

They might want the core rewritten in another language. They might want STM replaced with actors, or argue for mutability 'for performance'. They might want the semantic model redesigned, or the staged pipeline replaced with heuristics. They are not malicious – they simply assume the architecture is provisional, a starting point for negotiation rather than a finished foundation.

As you have seen, it is not.

2: The arena-seeker

Here the motivation is not technical at all. The project becomes a venue for resolving old arguments, validating preferred tools, or reenacting disputes imported from elsewhere. When the architecture does not bend, pressure escalates. When boundaries hold, frustration surfaces.

At that point refusal is often reinterpreted as hostility, silence as arrogance, and constraint as personal exclusion.

This is a category error. Refusal is governance. In Ooloi, it is exercised deliberately.

Why Refusal is Non-Negotiable

If the core were open to redesign, plugin contracts would break. Semantics would drift. Stages in the rendering pipeline would start interfering with each other. Concurrency guarantees would dissolve. Correctness would become probabilistic – which is to say, the system would regress to precisely the type of architecture Ooloi was built to escape.

By enforcing architectural closure, contributors learn where pressure will not be applied. Plugin authors learn what will not change. Users get stable behaviour. The system remains intelligible.

Boundaries are not unkind. They are protective.

Open Source Without Negotiation

​Ooloi is open source in a precise, literal sense: inspectable, forkable, extensible, durable.

It is not open in the sense of open-ended architectural debate. It is not open in the sense of consensus-driven semantics. It is not open in the sense of renegotiating authority with each new voice that arrives.

The core is not a public workshop. It is a composition. Collaborative compositions exist – devised theatre, collectively improvised music – but they are specialised forms suited to particular purposes, not universal methods. Ooloi's architecture is not that kind of work. Its structure must be fixed before others can build upon it.

The bazaar is not inside the cathedral; it is outside, at the gate, where plugins flourish without threatening the foundations.

The Gate & the Bazaar

The Penitenziagite! post argued that architecture should not shout incomprehensible demands at its users. This post argues the complement: governance should not shout incomprehensible demands at its contributors.

Ooloi's structure is explicit. There is the cathedral/scriptorium: the core, architecturally closed and semantically fixed, where the hard problems are solved. There is the library: canonical plugins and reference implementations, where patterns are demonstrated rather than debated. And there is the gate and the bazaar beyond it: the plugin ecosystem, open and multilingual and creative, but separated from the core by a boundary that preserves the integrity of the whole.

This is not a contradiction. It is a design pattern.

A stable centre enables a flourishing perimeter. A closed semantic core enables an open ecosystem. A cathedral enables a bazaar – but only if the gate between them holds.

0 Comments

First Window

27/1/2026

12 Comments

 
Picture
This is the very first window Ooloi has opened. Ever.

Not a console command or REPL experiment - a window created through the infrastructure completed yesterday (ADR-0031), using the new UI Specification Format (ADR-0042) that amongst other things makes all UI elements accessible to plugins as first-class citizens.

Another quiet decision: localisation from the start. ADR-0039 establishes that every UI string is translatable from day one, using GNU gettext's standard .po format. The tooling ecosystem is mature: Poedit, Crowdin, Transifex, Weblate, Lokalise, POEditor, OmegaT. Translators know these tools. Workflows exist. Nothing proprietary, nothing invented here.
​
Not retrofitted later. Built in.
12 Comments

Frontend Events: One Evening's Work

27/1/2026

3 Comments

 
Picture
Well, that was quick! The multi-tiered frontend event infrastructure is complete and implemented. One evening's work added the Event Router, the Rendering Data Manager, and the Fetch Coordinator. This implements ADR-0031 and shows that having the implementation architected in detail before writing the code saves a lot of time. I'd expected to be busy with frontend events for some time.

Now that that's out of the way comes what it enables: windows, dialogs, menus, notifications. I'll be working with JavaFX, cljfx, AtlantaFX: what's called 'UI chrome'.

It's concrete work without semantic subtleties for a change: does the window open? Does the NordDark theme apply correctly? Does the dialog render? Aesthetic decisions instead of semantic ones.

I expect these blog posts will turn quite practical in tone for a while, as this is standard engineering, plumbing, connecting things, turning detailed ADRs into working code. Quite relaxing, as a matter of fact.

And I can now, after 18 months, finally give in to that desire to actually open a window. Fresh air!
3 Comments

The Final Bit of Engine in Place

25/1/2026

0 Comments

 
Picture
Today, hierarchical key signature overrides were completed. Global key signatures can now be overridden at the instrument level as well as the staff level, as many times within a measure as required, with fully deterministic accidental handling. The updated ADR-0035 documents the algorithm.

This sounds narrow. It isn't. The ability to handle this correctly, without manual intervention or heuristic guesswork, required everything underneath it to be correct first. The last piece going in means the semantic aspect of the engine is complete.

Eighteen months of invisible work, ended.

The focus now shifts to the frontend event system, then to opening windows, etc. The infrastructure phase succeeded by disappearing; the next phase will succeed by appearing. Different disciplines, different anxieties.

I find it difficult to articulate what this moment feels like. The closest analogy I have is from composition: finishing a score and waiting for the first rehearsal.
​
A carefully prepared potentiality, awaiting concretion. 
0 Comments

Why Ooloi Doesn't Need a DAW

21/1/2026

9 Comments

 
Picture
For decades, orchestral playback has been organised around an absence of trust.

The score was not considered precise enough to stand on its own, so it had to be translated. MIDI became the intermediary. DAWs became the place where music was made to behave. Templates grew until they resembled orchestras-in-storage. Machines were added not because the music required it, but because the protocol did.

Ooloi takes a different position.

The score is treated as the authoritative description of the music. Pitch, timing, articulation, phrasing, microtonality and humanisation are not annotations awaiting interpretation elsewhere. They are part of the structure. Playback does not correct the score. It follows it.

For that reason, Ooloi has no MIDI output in the core. Audio is produced entirely by frontend plugins: VST/AU instruments, SoundFonts, synthesis engines. The backend never allocates channels, never bends pitches, never streams audio. It manages musical structure. Plugins turn that structure into sound. The instruments run inside Ooloi, not in an external DAW waiting for MIDI.

Pitch is represented symbolically and exactly. A note is not a frequency approximation or a MIDI pitch with heavy makeup but something like "C###4+50". A sustained chord can contain a continuously glissing inner voice without splitting staves, duplicating instruments, or consuming additional channels. There is no pitch-bend choreography, no controller bookkeeping, no library-specific workaround logic. The DNA soup is gone.

For readers coming from notation, this restores the score's authority. Slurs, dynamics, accents, register and phrasing are no longer hints for later repair. They are the performance.

For readers coming from virtual instruments, this architecture removes entire categories of work that have become normalised:

- No permanent DAW templates holding a full orchestra 'just in case'
- No slave machines preloading instruments that never play
- No CC drawing to approximate phrasing already present in the notation (the work that currently keeps Hans Zimmer's assistants employed)
- No channel allocation strategies for divisi or microtonality
- No waiting for templates to load before hearing a single note

Because the semantic model captures what is actually written, playback plugins can analyse the score and load only what is required. If a piece contains no contrabassoon, no contrabassoon need exist in memory. If a technique is missing in one library, another can be invoked for that passage alone. Routing, balance and reverberation can follow from structure, not from global assumptions.

This is why large template-based setups become unnecessary. Not because of optimisation tricks, but because they were compensating for a semantic gap between notation and sound. The architecture closes that gap.

Do DAWs still matter? Yes, but later. Mixing, sound design, video synchronisation and final delivery remain DAW territory. What changes is that the DAW is no longer required to make the music behave like music.

Ooloi does not replace the DAW.

It removes the need for the DAW to do a job it was never meant to do.
9 Comments

Music for Computer Scientists

10/1/2026

0 Comments

 
Picture
​A few weeks ago I wrote a post explaining computer science terminology to musicians. This is the inverse: an explanation of music notation for programmers who assume the domain is simpler than it is.

That assumption is common. It's also expensive. Most notation software has been written by very competent engineers who underestimated the problem. The result is systems that work impressively until they don't – at which point they fail in ways that seem arbitrary to users but are, in fact, architectural.

This post explains why.

Notation Is Not MIDI with Graphics

Picture
The most damaging assumption programmers bring to this domain is that music notation is a visual layer over time-stamped events. Work with audio software, game engines, or digital music for long enough, and this seems obvious: notes have start times, durations, and pitches. Notation just draws them nicely.

This is wrong in a way that corrupts everything downstream.

Consider two representations of identical duration:

  • (a) quarter note
  • (b) dotted eighth tied to sixteenth

These produce the same acoustic event. They do not mean the same thing. The first is a single rhythmic impulse sustained. The second implies a specific re-articulation point encoded in the notation itself. Performers read these differently. Conductors might even beat them differently. The semantic distinction is not ornamental.

MIDI cannot represent this distinction. It knows only NOTE_ON, NOTE_OFF, and duration. Notation systems built on MIDI-like assumptions inherit this blindness and spend their entire existence fighting it.

Music notation encodes musical meaning, not acoustic events. The implications of this single fact occupy the rest of this post.

Time Is Not Integers

Picture
Programmers reach instinctively for integer representation. MIDI uses ticks – typically 480 or 960 per quarter note. DAWs use samples. The assumption is that any temporal precision can be achieved by choosing a sufficiently small quantum.

This is false for music notation.

Consider a simple case: a quarter-note triplet against regular eighth notes. The triplet divides the beat into thirds; the eighths divide it into halves. To represent both exactly in a tick-based system, you need a tick count divisible by both 2 and 3. Fine: use 6 subdivisions.

Now add a quintuplet in another voice. You need divisibility by 2, 3, and 5: LCM = 30.

Now consider what real music does. Chopin writes nested tuplets. Ferneyhough writes 7:6 against 5:4 against 3:2. Elliott Carter writes simultaneous streams at different tempi. The required tick resolution grows combinatorially:

Picture
where di are tuplet denominators and k is your base resolution. For complex contemporary music, this can exceed 10^6 ticks per beat, at which point integer overflow becomes a real concern and accumulated floating-point error in tempo calculations produces audible drift.

The solution is obvious once stated: rational arithmetic. A quarter-note triplet is exactly 1/3 of a half note. No approximation. No accumulated error. The arithmetic is exact because the representation matches the domain.
​
  • triplet quarter = 1/3 × 1/2 = 1/6 of whole note
  • regular eighth  = 1/8 of whole note

These don't share a finite decimal expansion. They don't need to. Rationals are closed under the operations music requires.

Clojure provides this natively. Most notation software doesn't use it. The consequences appear everywhere timing matters – which in notation is everywhere

The Structure Is Not a Tree

Picture
Programmers expect hierarchical data. XML, JSON, ASTs, DOM trees – the mental model is that complex structures decompose into nested containers. Parent nodes own child nodes. Traversal is well-defined.

Music notation has multiple simultaneous hierarchies that do not nest cleanly.

A single note participates in:
  • Metric structure: beat → measure → section
  • Rhythmic grouping: tuplet → beam group → phrase
  • Pitch organisation: voice → chord → harmonic progression
  • Measure layout: measure → staff → instrument → system → page
  • Notational conventions: slur, dynamic hairpin, articulation group

These hierarchies intersect. They do not nest. Consider cross-staff notation: a chord where some notes appear on the treble staff and others on the bass. Which staff 'owns' the chord? Neither. Both. The question assumes a tree structure that doesn't exist.

Or consider voice exchange: soprano and alto swap pitches mid-phrase. The melodic line (a horizontal relationship) contradicts the voice assignment (a vertical relationship). Both are musically meaningful. Neither subsumes the other.

Grace notes exist precisely at the intersection of conflicting hierarchies. They have pitch (placing them in a voice) but steal time from adjacent notes (making their metric position contextual). They may or may not take accidentals from the main-note context. The rules vary by historical period.

Systems that force music into a single hierarchy spend enormous effort on edge cases that are only 'edge' cases because the data model is wrong.

Context Is Non-Local: The Accidental Problem

Picture
​Here is a concrete example of why music notation is harder than it looks.

Question: Does this F need a sharp sign?

Answer: It depends on:
  1. The key signature (established possibly pages earlier)
  2. What happened earlier in this measure in this voice
  3. What happened earlier in this measure in other voices on the same staff
  4. What happened earlier in this measure in other staves (in keyboard music, an F♯ in the left hand may affect an F in the right)
  5. Whether there's a tie from the previous measure
  6. Whether this is a grace note (different rules apply)
  7. Publisher conventions (some always mark cautionary accidentals, some don't)
  8. Historical period (18th-century conventions differ from 20th-century)

A naive algorithm checks each note against previous notes in the measure. This is O(n) per note, O(n^2) per measure. Fine for simple music.

Now add multiple voices. The F in the soprano might be affected by an F♯ in the alto, depending on conventions. You need to track alterations across voices. If voices cross staves (as in keyboard music), the interactions multiply.

Now add simultaneity. What happens when two voices sound the same pitch at the same instant but with different accidentals? Yet another edge case difficult to catch when imprisoned in the Jail of Recursive Descent.

Now add grace notes. A grace note at the beginning of a measure might be notated at the barline but sound at the end of the previous measure. Does its accidental affect the next measure? Does the next measure's key signature affect it?

The dependency graph for accidentals is not a simple sequence. It's a directed acyclic graph with edges determined by temporal position, voice membership, staff assignment, and notational category. Correct handling requires topological sorting with domain-specific edge semantics.

Most notation software handles this with heuristics: rules-of-thumb that cover common cases and fail on uncommon ones. The failures aren't bugs in the usual sense. They're consequences of architectural decisions made decades ago when the problem was less well understood.

Ooloi handles this through what I call the 'timewalker' – a transducer that processes musical events in semantic order (not storage order) allowing full temporal context accumulation. The accidental algorithm becomes stateless over its input stream: given the same sequence of musical facts, it produces the same decisions. Deterministically. Every time.

The complexity is still O(n · v) for n events and v voices, but the constant factor drops dramatically because traversal and processing are separated. The transducer handles navigation; the algorithm handles meaning.

Concurrency Is Not Optional

Picture
​Here is where most notation software fails silently.

A modern computer has multiple cores. Users expect responsiveness: type a note, see it appear immediately. But notation isn't like a word processor where inserting a character affects only nearby layout. Changing one note can alter accidentals throughout a measure, reflow an entire system, or invalidate cached engraving calculations across pages.

The traditional approach is to serialise everything. One thread handles all mutations. The UI blocks or queues. This is why notation software freezes when you paste a large passage, or why collaborative editing remains essentially unsolved in this domain.

The problem deepens when you consider what 'correct' means during an edit. If a user changes an F♮ to an F♯ in measure 4, the accidental state of measure 5 depends on this change. But if the rendering thread is currently drawing measure 5, what does it see? The old state? The new state? Some inconsistent mixture?

Mutable state with locks doesn't solve this; it creates a new category of bugs. Deadlocks. Race conditions. Heisenbugs that appear only under specific timing. A very difficult work environment indeed, and one where diminishing returns becomes a real impeding factor.

The functional approach is different. If musical data is immutable, the question dissolves. The rendering thread has a consistent snapshot – always. The editing thread produces a new snapshot. There's no moment of inconsistency because there's no mutation.

This is what Software Transactional Memory provides in Clojure. Transactions compose. Reads are always consistent. Writes are atomic. The system guarantees that no thread ever sees a half-updated score.

The performance implications are substantial. Ooloi's STM handles heavy contention without the coordination overhead that serialised systems pay constantly. The bottleneck shifts from synchronisation to actual work.

Real-time collaboration becomes architecturally possible. Two users editing the same passage don't corrupt each other's state; they produce alternative futures that the system can merge or present as conflicts. This isn't a feature bolted on afterwards. It's a consequence of representing music correctly from the start.

Engraving Is Constraint Satisfaction

Picture
Ravel being difficult
​Programmers sometimes assume that once you have the musical data, displaying it is straightforward. Calculate positions, draw glyphs, done.

This underestimates the problem by roughly an order of magnitude.

Consider accidental placement in a dense chord. Multiple accidentals must avoid colliding with each other, with noteheads, with stems, with ledger lines, and with accidentals in adjacent chords. The placement rules aren't arbitrary – they encode centuries of engraving practice optimised for readability.

This is a constraint satisfaction problem. In the general case, it's NP-hard. Real systems use heuristics, but the heuristics are subtle. Gould's Behind Bars – the standard reference on notation practice – devotes many pages to accidental stacking alone.

Now multiply by every other engraving decision: beam angles, stem lengths, tie curves, slur routing, dynamic placement, tuplet brackets, ottava lines, system breaks, page breaks. Each interacts with the others. Change a stem length and the beam angle needs adjustment; beam ends need to follow sit-straddle-hang rules and might both move. Change a beam angle and adjacent voices may collide.

LilyPond's engraving quality comes precisely from treating this as a serious optimisation problem. Its page-breaking algorithm runs a variant of the Knuth-Plass line-breaking algorithm (developed for TeX). Its spacing uses spring-based constraint systems. The 'simple' rendering layer contains some of the most sophisticated code in the system.

Interactive notation software faces an additional challenge: these calculations must be fast enough for real-time editing. You can't spend ten seconds optimising layout every time the user adds a note. The tension between quality and responsiveness has driven much of the architectural evolution in this field.

Historical Conventions Are Not Bugs

Picture
​A programmer encountering music notation for the first time will find countless apparent inconsistencies. Surely these could be rationalised?

No. Or rather: not without destroying information.

A fermata on a note means 'sustain this note'. A fermata on a barline means 'pause here'. A fermata on a rest means something slightly different again. These distinctions emerged from practice. Composers use them. Performers understand them. A system that normalises them into a single 'fermata event' loses musical meaning.

Grace notes in Bach are performed differently than grace notes in Chopin. The notation looks similar. The performance practice differs. A system that treats all grace notes identically will produce correct output that performers find misleading.

Clefs change meaning by context. A C-clef on the third line is an alto clef; on the fourth line, a tenor clef. Same symbol, different staff position, different meaning. This isn't legacy cruft – orchestral scores routinely use multiple C-clef positions because different instruments read different clefs.

Mensural notation (pre-1600) has entirely different rules. The same notehead shapes mean different things. Accidentals follow different conventions. Barlines serve different purposes. A truly comprehensive notation system must handle this or explicitly disclaim it.

The temptation to clean this up, to impose regularity, to treat historical conventions as technical debt – this temptation must be resisted. These conventions encode musical knowledge. Destroying them in the name of consistency destroys the knowledge.

The Performer Is the Point

Picture
​All of this serves a purpose that has nothing to do with computers.

Notation exists to communicate with humans. Specifically: performers who bring interpretation, physical constraints, and centuries of inherited practice to their reading.

This isn't sentimental. It has engineering consequences.

A page turn in the wrong place forces a pianist to stop playing or memorise a passage. This is a functional failure, not an aesthetic preference. The page-breaking algorithm must allow this to be modelled.

Awkward beam groupings obscure metric structure. The performer reads beats through beam patterns. Wrong beaming means wrong emphasis. The beaming algorithm must model this based on the currnent time signature.

Unclear voice leading forces performers to decode the texture before they can interpret it. The system must make voices visually distinct in ways that match musical distinctness.

Engraving choices that are mathematically equivalent may not be performatively equivalent. Two layouts might use the same space and avoid all collisions, but one reads naturally and the other requires active deciphering. The difference matters.

This is why notation is not a solved problem. The specification is 'communicate musical meaning to human performers'. That's not a format spec. It's a design constraint that touches every decision in the system.

Conclusion

Picture
Music notation looks like a data format problem. It is actually a meaning representation problem with a millennium of accumulated context.

The systems that fail – and most fail in some way – do so because they treat notation as something to be processed rather than something to be understood. They model the symbols without modelling what the symbols mean.

The systems that succeed take the domain seriously. They represent time exactly. They handle multiple hierarchies without forcing false containment. They process context correctly even when context is non-local. They treat engraving as a real problem, not a rendering detail. They preserve historical conventions because those conventions carry meaning.

This is why Ooloi's architecture looks the way it does. Rational arithmetic isn't ideology; it's the only way to represent tuplets exactly. Immutability isn't fashion; it's the only way to guarantee that accidental decisions are deterministic. Transducers aren't showing off; they're the cleanest and most efficient way to process a semantic stream with accumulated context. STM isn't over-engineering; it's the only way to achieve both correctness and responsiveness without sacrificing either.

The domain dictates the tools. Not the reverse.

0 Comments

And Only Then

9/1/2026

6 Comments

 
Picture
We have a new year, and it's time to make plans. Ooloi's architecture is now closed, and the work enters a new phase. What follows is a road map, not a schedule – no dates, no promises – but a logical progression.

These stages are different in nature from what has gone before. Conceptually simpler than the deep semantic work (what the music is, how it's represented and manipulated) or the infrastructure (server/client transports and roundtrips, monitoring, certificates). Everything below is comprehensively architectured and implementation-ready. The thinking is done; what remains is execution.

The Preparations

Event-Driven Client Architecture: The nervous system that lets the interface respond without freezing. (ADR-0022, ADR-0031)

Windowing System: Windows, menus, palettes, dialogs, notifications, connection status. The application becomes something you can see and touch. (ADR-0005, ADR-0038)

Multi-Mode Clients: Standalone operation, peer-to-peer connection, shared server connections. (ADR-0036)

Skija / GPU Rendering: The drawing substrate. GPU-accelerated graphics, paintlist caching, lazy fetching. The machinery for putting marks on screen. (ADR-0005, ADR-0038)

Hierarchical Rendering Pipeline: The transformation from musical structure to visual layout. (ADR-0028, ADR-0037)

Plugin System: First-class access from any JVM language. (ADR-0003, ADR-0028)

MusicXML: The first, limited version, implemented as a canonical plugin. Real scores entering the system. (ADR-0030)

And then – and only then – will the first staff line appear.
6 Comments

Six Degrees of Unification

6/1/2026

2 Comments

 
To implement what was described in the last blog post deterministically, ADR 0028, on the hierarchical rendering pipeline, and ADR 0037, about measure distribution, both have been updated. The rendering pipeline now has six stages rather than five.

The additional stage enables the behaviour discussed in the previous post, but also allows slurs, lyrics, dynamics, and other elements that require vertical space to adapt dynamically without introducing layout jitter.

What follows is a brief tour of the six pipeline stages. Each has a clearly defined role, a fixed direction of information flow, and no hidden feedback paths. Together, they transform musical structure into pages without iteration.

If you are a musician, you should be able to follow how the music moves from essential meaning to visual expression. If you are a developer, the architectural choices should be readable between the lines. In both cases, the ADRs contain the full technical detail.

Stage 1: Atoms

Each measure is processed independently and turned into engraving atoms: indivisible musical units that already contain noteheads, augmentation dots, accidentals, stems, articulations: everything that belongs together. A note or a chord is an atom, including everything at a fixed distance from that note or chord. Once an atom is computed, its constituent parts never move relative to each other, though they can be adjusted manually or converted by the user to pure graphics for Illustrator-like manipulation.
​
From these atoms, the system derives three facts about the measure stack: a minimum width, where atoms are simply lined up after one another (guaranteeing that nothing ever collides); an ideal width, based on proportional spacing from rhythmic density; and a gutter width – extra space required only if the measure begins a system. Courtesy accidentals caused by system breaks are accounted for here as space requirements, not as symbols. Ordinary courtesy accidentals are already part of the atom.

​Stage 2: Rhythmical Alignment

All measures in a stack contribute a rhythmic raster: the sequence of atom positions implied by their rhythmic content at ideal spacing. Stage 2 takes these per-staff rasters and aligns them into a single, stack-wide rhythmic grid, so that 'the beat structure' is shared across staves rather than each staff carrying its own local spacing. Because the system has both the rasters and the atom extents from Stage 1, it can adjust the aligned positions so that collisions are avoided while still preserving the intended proportional structure.

​Stage 3: System Formation

With rhythmical alignment complete, the score collapses to a one-dimensional sequence of measure stacks, each described only by stack minimum width, stack ideal width, and possible stack system-start gutter. System breaks are chosen using dynamic programming, and a scale factor is computed for each system so that ideal proportions are preserved as well as possible within the available width. At the same time, system preambles (clefs, key signatures) are fully determined. Apart from these, the stage produces only break decisions and scale factors; no measure content is positioned yet.

​Stage 4: Atom Positioning

The abstract decisions from system formation are applied. Each atom is positioned horizontally by scaling its ideal spacing according to the scale factor of its system. Because atoms were defined with purely relative internal geometry, they can be moved without recomputation. This stage is a pure projection from musical proportions to absolute coordinates.

​Stage 5: Spanners

All connecting elements are resolved against the fixed atom positions: ties, slurs, hairpins, ottavas, lyric extenders. They adapt to the horizontal geometry they are given and never influence spacing upstream. System-start decorations live here as well: courtesy accidentals now appear in the gutter space that was explicitly reserved earlier.

​Actual system heights emerge at this stage as a consequence of what must be drawn – slurs, ties, lyrics, pedalling indications, hairpins – each claiming vertical space as required to avoid collisions. In this stage, braces, brackets, and instrument name indications are also computed for the left margin, as all information required to determine system grouping and extent is now available.

​Stage 6: Page Formation

Systems are distributed across pages using dynamic programming, this time over the actual system heights produced by the previous stage. As in Stage 3, the distribution is optimal with respect to the available space. Once page breaks are chosen, layout is locked and no earlier stage is revisited. At this point, all rendering decisions have been made. The score can now be drawn directly from the cached paintlists.
2 Comments

System-Break Courtesy Accidentals

5/1/2026

0 Comments

 
Picture
Standard practice in many house styles is to show a courtesy accidental at the start of a new system when a tied note continues across a system break. In traditional notation workflows, this is handled manually: the engraver adds or forces the accidental after layout.

That manual step has consequences. A courtesy accidental has width. Adding it can push spacing past a threshold, move a system break, or reflow measures. A small local correction can trigger a cascade elsewhere, sending the engraver back to the same passage again. This is not a matter of care or skill. It is a side effect of heuristic layout combined with post-hoc correction.

Ooloi takes a different path.

Courtesy accidentals that exist because of a system or page break are derived, not edited. Ooloi has user settings to control preferred behaviour – such as whether these accidentals appear at all system breaks, page breaks only, or not at all. The required space is known before layout begins. System and page breaks are explicit decisions, and the distribution pass incorporates these accidentals exactly once.

Edit the score and the layout is recomputed.
Change a preference and the layout is recomputed.

There is no iterative correction loop, no heuristic adjustment, and no manual cleanup phase. Layout-dependent notation is a deterministic consequence of the score, its breaks, and the engraver’s stated preferences.

0 Comments

Arc

4/1/2026

0 Comments

 
Picture
I keep an internal development log. It's not public, partly because publishing it would create expectations about sequence and timing that I have no intention of meeting. But something happened to its structure recently.

For over a year, the log tracked numbered phases. Phase 1 through Phase 6, each with clear boundaries, some of them with sub-phases. The numbers implied I knew what came next.

After Phase 6, I was supposed to implement Phase 7 (event-driven client architecture) and Phase 8 (windowing system). Opening a window was 'weeks away'. That's what the plan said.

That's not what happened.

Something – veteran instinct, fifty years of pattern recognition too deep to articulate – said: complete the semantic layer first. Not the plan. Not what 'agile' methodology recommends. But the foundations needed to handle real musical complexity before anything was built on top of them.

So instead of windows, I implemented the full semantic layer. Time signatures, key signatures, remembered alterations – the systems that determine what accidentals print and when. The hard problems in notation software, the ones that have resisted clean solutions for forty years.

I've written about that work as it happened. What I hadn't written about, until now, is what it revealed about the plan itself.

​The development log no longer uses numbered phases for future work.

This isn't abandonment of structure. It's recognition that the work has entered a different mode. The section heading now reads 'Future Stages' with a note: 'Not numbered phases – sequencing may shift based on what the work reveals.'

That sentence took eighteen months to earn. The plan implied I knew the sequence. The reality is that the architecture now tells me what it needs. The foundations are proven; what follows is revelation, not construction. And I now need to listen.

​For eighteen months, the work was architectural: designing possibilities, extending the system, proving it could handle what I asked of it. That mode of thinking was adaptive. It built what now exists.

That mode of thinking is now dangerous.

The guardrail, however, is surprisingly simple. A single principle: if rendering something changes the semantics of what's being rendered, the logic is wrong. Not 'possibly wrong' or 'worth reconsidering'. Wrong as in 'don't go down that path; retrace your steps entirely'.

This sounds obvious, but it's deceptively easy to violate. The instinct to adjust, to consider alternatives, to make something 'look better' by feeding visual decisions back into musical ones – these reflexes served construction. They now threaten what's been built.

The architecture is now closed. It’s no longer fluid in any sense.​ Rendering reveals; it doesn't renegotiate. I may return to this topic, because the implications run deeper than they first appear.
0 Comments

    Author

    Peter Bengtson –
    Cloud architect, Clojure advocate, concert organist, opera composer. Craft over commodity. Still windsurfing through parentheses.

    Search

    Archives

    January 2026
    December 2025
    November 2025
    October 2025
    September 2025
    August 2025
    July 2025
    June 2025
    April 2025
    March 2025
    September 2024
    August 2024
    July 2024

    Categories

    All
    Accidentals
    Alfred Korzybski
    Architecture
    Benchmarks
    Clojure
    CLOS
    Common Lisp
    DDD
    Death Of Igor Engraver
    Documentation
    Donald E Knuth
    Dorico
    Dynamic Programming
    Finale
    FrankenScore
    Franz Kafka
    Frontend
    Functional Programming
    Generative AI
    GRPC
    Igor Engraver
    Jacques Derrida
    JVM
    License
    LilyPond
    Lisp
    Localisation
    MIDI
    MPL 2.0
    MuseScore
    MusicXML
    Ooloi
    Ortography
    Pitches
    Playback
    Plugins
    Python
    QuickDraw GX
    Rendering
    Rhythm
    Rich Hickey
    Road Map
    Scheme
    Semiotics
    Sibelius
    Site
    Skia
    Sponsorship
    UI
    Umberto Eco
    Vertigo
    VST/AU
    Wednesday Addams

    RSS Feed

Home
​Overview
Documentation
About
Contact
Newsletter
Ooloi is an open-source desktop music notation system for musicians who need stable, precise engraving and the freedom to notate complex music without workarounds. Scores and parts are handled consistently, remain responsive at scale, and support collaborative work without semantic compromise. They are not tied to proprietary formats or licensing.
​
Ooloi is currently under development. No release date has been announced.


  • Home
  • Overview
    • Background and History
    • Project Goals
    • Introduction for Musicians
    • Introduction for Programmers
    • Technical Comparison
  • Documentation
  • About
  • Contact
  • Home
  • Overview
    • Background and History
    • Project Goals
    • Introduction for Musicians
    • Introduction for Programmers
    • Technical Comparison
  • Documentation
  • About
  • Contact