[HN Gopher] Xenharmlib: A music theory library that supports non...
       ___________________________________________________________________
        
       Xenharmlib: A music theory library that supports non-western
       harmonic systems
        
       Author : retooth
       Score  : 194 points
       Date   : 2025-07-08 22:37 UTC (2 days ago)
        
 (HTM) web link (xenharmlib.readthedocs.io)
 (TXT) w3m dump (xenharmlib.readthedocs.io)
        
       | ksr wrote:
       | Fascinating. I'm working on many adjacent pieces myself - my name
       | for this whole initiative is music-i18n because I see it as the
       | equivalent of adding software layers to support world languages
       | and locales - in this case musical ones.
       | 
       | I am especially interested to hear your plans / thoughts about
       | the following:
       | 
       | - Supporting non-ET tunings
       | 
       | - Supporting tetrachords and other scale building blocks (like
       | Arabic ajnas)
       | 
       | - Importing/exporting MusicXML
       | 
       | - Exporting to MIDI
       | 
       | Thanks!
        
         | retooth wrote:
         | Hi! I'll try to answer in order:
         | 
         | 1. Just Intonation and non-linear temperaments are on the
         | roadmap, but there are a couple of design problems I still have
         | to figure out, mainly how to have a consistent definition of
         | interval objects in regards to transposition if the distances
         | between notes are uneven. It works nicely, if one uses multi-
         | dimensional tunings, e.g. in a 5-Limit tuning with 3 dimensions
         | every interval obtained from two notes can be applied to any
         | other note as a measure of transposition distance, but once you
         | reduce it to one dimension you can have two notes which form an
         | interval that can not be applied to every note without reaching
         | a note that is outside the temperament.
         | 
         | 2. Tetrachords are already supported and can be easily defined
         | using the scale object. There is no quartertone notation yet,
         | but if you are happy with Up/Down Notation you can analyze
         | arabic ajnas by using EDOTuning(24) as the base. Currently
         | there is no pitch/note sequence object, so downward scale
         | movement in maqams can not be properly defined, but if you are
         | interested only in the harmonic qualities, scales should do.
         | 
         | 3. MusicXML sadly does not have good support for non-12-EDO
         | tunings. You can define quartertone accidentals by providing
         | floats (like 0.5) as accidental values, but this gets
         | increasingly difficult if you want to do anything other than
         | 24-EDO. I looked into the MEI format as it supports at least
         | turkish makam accidentals, but a more generalized semantic
         | definition for arbitrary EDOs seems to be out of reach for the
         | foreseeable future. One could however think of supporting MEI
         | for a couple of tunings (like 24- or 53-EDO)
         | 
         | 4. MIDI is also somewhat difficult. There is the MPE
         | specification which allows individual note bending, however it
         | is not supported by any python library as far as I can tell.
         | One could try to hack something with channel pitch bends, but
         | it would be limited to playing 16 notes at the same time.
         | 
         | I am still looking for contributors, so if you are interested
         | in these things, feel free to contact me ;)
        
           | ksr wrote:
           | Thanks for your answer. To me, the thrill of modeling the
           | rich and vast domain of music practices across the world is a
           | never-ending source of joy and discovery. To answer your
           | specific points:
           | 
           | 1. In my own similar library
           | (https://github.com/infojunkie/scalextric) I decided to
           | pragmatically throw an exception if the transpose method is
           | called on an untransposable scale... At the moment I'm not
           | trying very hard to handle all the cases of transposability -
           | I'm sure there's a mathematical object like a group or ring
           | to describe such cases.
           | 
           | 2. I'll read your code to understand better how you handle
           | sub-scale sequences. I would like to revisit my own approach
           | to start at the dyads (sequence of 2 tones plucked from a
           | given tuning) and build up longer sequences from those. I
           | think this would allow to distinguish between ascending and
           | descending sequences in a natural way.
           | 
           | 3. I've spent quite a bit of time with MusicXML, and some
           | time with MEI as well.. Yes, neither format has a model for
           | arbitrary tunings which is a glaring gap. MusicXML does
           | represent the full set of visual accidentals (including
           | custom SMuFL glyphs) as well as per-note decimal pitch
           | alterations that can accommodate any cent value. MEI also
           | represents a reasonably complete set of accidentals although
           | it's a closed set, as opposed to MusicXML's open set of
           | accidentals. MEI supports a few pre-defined tunings which
           | also falls short of generality. In addition, MEI does not
           | support per-note pitch alterations, which makes it even
           | harder to represent anything outside the tunings that it pre-
           | defines.
           | 
           | There's unfortunately little activity to update these formats
           | to include general tunings. I'm having discussions in both
           | communities, maybe you'd like to add your voice:
           | https://github.com/music-encoding/music-encoding/issues/1167,
           | https://github.com/w3c/musicxml/discussions/586.
           | 
           | 4. I've also spent quite a bit of time on MIDI
           | microtonality... There are 3 main approaches that I'm aware
           | of:
           | 
           | a. MIDI Tuning System which maps the 128 MIDI notes to
           | arbitrary frequencies.
           | 
           | b. Pitch bending which has the limitation that you mentioned
           | above. MPE is essentially an organized methodology for
           | reusing empty MIDI channels in a round-robin fashion for
           | pitch bends and other controller effects.
           | 
           | c. MIDI 2 supports per-note controller settings out of the
           | box, thereby superseding MPE.
           | 
           | My current focus is to create a MusicXML => MIDI conversion
           | pipeline that supports arbitrary tunings, using Verovio as
           | the MIDI conversion engine. I am of course "inventing" new
           | MusicXML elements to represent these tunings and their
           | mappings (and MEI elements too, because Verovio represents
           | its own internal state based on MEI). My aim is to produce a
           | MIDI version of the canonical Sagittal Example
           | (https://www.sagittal.org/exmp/index.htm) from a MusicXML
           | file.
        
             | retooth wrote:
             | 1. Thanks for the link. I am reading a bit of your code
             | right now :) Also nice to see that it is GPL licensed too.
             | In regards to intervals: What still confuses me in the
             | design process is that in certain uneven tunings, (e.g.
             | Pythagorean) there seems to be two approaches to naming
             | intervals. One would be an "absolute" approach, where
             | intervals that do not form a 5/4 ratio would not be
             | considered a major third, and one "functional" approach,
             | where the exact frequency ratio does not matter and the
             | interval name is simply deduced from the note names (D to
             | F# is a major third even tough the ratio is 81/64)
             | 
             | 2. I'm not sure what you exactly mean by sub-scales. Imho
             | the best approach in xenharmlib to define maqams from ajnas
             | would be to define ajnas as interval sequences in 24-EDO
             | and then concatenate them with + to a maqam interval
             | sequences. Then you can use the result to define maqams on
             | any note.
             | 
             | 3. Thanks for the links. I will add something soon ;) I
             | also tried my luck on the MEI Slack channel but did not
             | receive any response. I think MusicXML might be a good
             | format for exporting xenharmonic data, but importing from
             | it is tricky. In certain temperaments the cent values have
             | so many digits after the point that importing would be
             | forced to apply heuristics for rounding errors :/
             | 
             | 4. Option a) is currently the one I use, but I am somewhat
             | unhappy about it, because it requires a "tacit"
             | understanding between two programs of how exactly the 128
             | notes are redefined (also 128 is not plenty, just think of
             | turkish makam that has 53 notes per octave. That is barely
             | 2 octaves in this system). My hopes are currently on MIDI
             | 2.
        
               | ksr wrote:
               | 1. Regarding naming of intervals, this has confused me
               | for months, until I understood (or convinced myself) that
               | there are in fact 2 different things that are called
               | "intervals": intervals between tuning pitches (which is
               | your first example) and intervals between scale notes
               | (your second example). Thinking of them as different
               | things (and calling them differently) has helped me a lot
               | with modeling musical objects in scalextric. For example,
               | tuning intervals in different tunings (12-TET vs.
               | Pythagorean) can end up having the same logical interval
               | name because they are approximating the same logical
               | relationship between notes even though the physical
               | frequencies are different.
               | 
               | 2. sub-scales = what you call interval sequence.
               | 
               | If you don't mind, we can continue this conversation by
               | email. Mine is in my profile on HN.
        
           | elihu wrote:
           | > There is the MPE specification which allows individual note
           | bending, however it is not supported by any python library as
           | far as I can tell. One could try to hack something with
           | channel pitch bends, but it would be limited to playing 16
           | notes at the same time.
           | 
           | In practice, that's not usually a problem. That's a lot of
           | polyphony. Technically if you're following the MPE spec, you
           | only get 15 channels because one channel is reserved for
           | sending commands that affect all voices at once. (Like you
           | can send one pitch bend on the reserved channel and have it
           | affect all 15 other channels at once. Likewise for program
           | change and CC messages.)
           | 
           | MPE is kind of a weird way to do things but it actually works
           | pretty well. And one of the nice things about it is that if
           | you go to the trouble to support MPE, it's a pretty easy step
           | to support pre-MPE multitimbral synths -- though each one
           | tends to have its own quirks that have to be worked around.
           | 
           | I've been working on a just intonation MPE controller, and
           | have gotten it to work with a bunch of old 80s-90s-2000's
           | hardware synths. I've considered that it might be worthwhile
           | to eventually split that code out into a separate library so
           | other projects that want to use old
           | Yamahas/Rolands/Korgs/E-mus etc.. in a microtonal way they
           | don't have to reinvent the wheel.
        
       | bntr wrote:
       | A bit tangential, but I recently made a xenharmonic-related
       | library too - focused more on the visual/harmonic space side:
       | 
       | https://github.com/bntre/cs-rationals/blob/master/RationalsE...
       | 
       | Demo piece: https://www.youtube.com/watch?v=y_x4vtS_I7w
        
         | retooth wrote:
         | Oh, neat :) This looks really cool. In one of the upcoming
         | versions of xenharmlib I am planning to add hooks for
         | visualization plugins, so structures can be rendered in
         | JupyterLab. Maybe you would be interested in contributing,
         | however it will take some time before JI is supported.
        
       | bntr wrote:
       | My actual question: do you use xenharmlib for composing?
       | 
       | I assume this is your album:
       | https://fabianvallon.bandcamp.com/album/a-different-path-for...
       | 
       | Was xenharmlib used in it, or some other software?
        
         | retooth wrote:
         | Yes, I do. For the actual score composition I used Ableton, but
         | xenharmlib can export SCL files to define microtonal scales,
         | which then can be imported in Ableton (a lot of other DAWs and
         | VSTs support this format too).
         | 
         | For the most part however I use xenharmlib for theoretical
         | aspects of music. I got interested in the "31 Equal Divisions
         | per Octave" tuning a couple years ago, because of its
         | psychoaccustic potentials, but thinking about chords, modes,
         | notation in 31-EDO made my head hurt, so I built the library to
         | help me think and answer my questions.
        
       | max_ wrote:
       | Is there a good resource to learn basic music theory?
       | 
       | Like learn what the meaning of A B C and other letters mean?
       | 
       | And how the come together to make actual music?
        
         | retooth wrote:
         | I often used this for reference:
         | https://musictheory.pugetsound.edu/mt21c/MusicTheory.html
        
           | max_ wrote:
           | Thank you so much. This is brilliant.
        
       | sim7c00 wrote:
       | is there somethin similar in C++. this is really useful, but most
       | VST etc. afaik get built in c++, i know for example JUCE
       | framework to build em uses c++ so to me that seems a practical
       | language for such a tool
       | 
       | (focussing on the last bit of the article mentioning it can be
       | used in digital instruments / dsp. totally agree!)
        
         | retooth wrote:
         | Since xenharmlib is written in python it is not suitable for
         | real-time audio because of the latency that an interpreted
         | language introduces.
         | 
         | I think if someone was willing they could port the library to C
         | or Rust rather easily, because apart from Exceptions the coding
         | style is functional and stateless. AFAIK Rust has some
         | libraries that provide a VST interface.
        
       | mkesper wrote:
       | Fantastic, my suggestion would be to rename to Xenharmoniclib,
       | though. harmlib sounds...harmful? to me
        
         | userbinator wrote:
         | It would be a suitable name of a library for exploiting the Xen
         | hypervisor.
        
       | bhalahi wrote:
       | Does this include the socialist, communist, and banana republic
       | dictatorial harmonic systems?
        
       ___________________________________________________________________
       (page generated 2025-07-10 23:01 UTC)