# \[ANN\] Announcing MusicTheory.jl

**URL:** <https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444>\
**Category:** Package Announcements\
**Created:** [January 6, 2024, 8:56pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444 "2024-01-06T20:56:10Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [January 6, 2024, 8:56pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/1 "2024-01-06T20:56:10Z")

</div>

# MusicTheory.jl

I’m happy to announce the new package [MusicTheory.jl](https://github.com/dpsanders/MusicTheory.jl).  
The goal of the package is to provide a foundation for representing musical objects in a Julian way.

The main challenge has been to find the right abstraction for each type of object.  
[I deliberately have not looked in detail at other packages.]  
Currently the package is based on the structures of “Western” music, and in particular on semitones (rather than smaller subdivisions).

Contributions in the form of Pull Requests are very welcome!

# Outline

The package is based around `Pitch`es, for example `C♯[4]`, and `Interval`s;  
Everything else is constructed from these.

E.g. a scale is a way of dividing up an octave into a sequence of intervals; this sequence then repeats each octave. A natural way to represent this in Julia is thus a vector of `Interval`s, representing the scale steps, wrapped into an infinite iterator. [The naturalness of this representation took a while to dawn!]

# Features

- Pitches using scientific notation, e.g. C4 for middle C
- Intervals
- Arbitrary scales (modes)
- Notes and rests with durations
- Motifs using scale tones, such as arpeggios

# Partially implemented

- Chords
- Triads

# Desired features (not yet implemented)

- Iterate scales in a descending direction
- Ability to play notes
- Export to Lilypond, Midi, MusicXML
- Interaction with related Julia packages from the [JuliaMusic](https://github.com/JuliaMusic) org

# Basic usage (see also the README)

```julia-auto
julia> using MusicTheory, MusicTheory.PitchNames

julia> C♯
C♯

julia> typeof(C♯)
PitchClass

julia> C♯[4]
C♯₄

julia> typeof(C♯[4])
Pitch

julia> Interval(C[4], E[4])
Major 3rd

```

# Example of using scales

```julia-auto
julia> show(major_scale) 
Interval[Major 2nd, Major 2nd, Minor 2nd, Major 2nd, Major 2nd, Major 2nd, Minor 2nd]

julia> scale = Scale(C[4], major_scale) 
Scale{Pitch}(C₄, Dict{PitchClass, Interval}(C => Major 2nd, E => Minor 2nd, B => Minor 2nd, F => Major 2nd, D => Major 2nd, G => Major 2nd, A => Major 2nd)) 

julia> scale_tones = Base.Iterators.take(scale, 8) |> collect; 

julia> show(scale_tones) 
Pitch[C₄, D₄, E₄, F₄, G₄, A₄, B₄, C₅]

```

---

<div class="post-metadata">

**Author:** ![TheLateKronos](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thelatekronos/32/12824_2.png) [@TheLateKronos](https://discourse.julialang.org/u/TheLateKronos)\
**Post date:** [January 6, 2024, 9:26pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/2 "2024-01-06T21:26:59Z")

</div>

Awesome! Do you have an idea in mind how how people might utilize the package?

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [January 6, 2024, 9:51pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/3 "2024-01-06T21:51:37Z")

</div>

Thanks – no, not really! There’s an example in the README of how I have used it to do a “computation” to do with a scale in thirds.

You can also just use it as a way to input a piece of music – although currently there’s no way to output it… 😉

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [January 6, 2024, 9:54pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/4 "2024-01-06T21:54:08Z")

</div>

One thing I had in mind was for e.g. ear training and generating random intervals to recognise / practise. @Datseris has done similar things in packages in the JuliaMusic org.

E.g. it would be relatively simple to write a function `random_interval` that generates a random interval and displays it, e.g. using Makie.jl, and asks you what type of interval it is. (I have some draft code for using Makie.jl that is not in the repo. Maybe I should put it there.)

---

<div class="post-metadata">

**Author:** ![TheCedarPrince](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thecedarprince/32/17323_2.png) [@TheCedarPrince](https://discourse.julialang.org/u/TheCedarPrince)\
**Post date:** [January 6, 2024, 10:00pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/5 "2024-01-06T22:00:40Z")

</div>

Radical. With some music theory knowledge and a bit more work on the package, one could create study flashcards for tools like Anki to drill you on practicing novel practice pieces. Like: Play this small variation at X bpm in X/X time signature.

Fun stuff @dpsanders! Love seeing stuff like this emerge!

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [January 6, 2024, 10:41pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/6 "2024-01-06T22:41:35Z")

</div>

Are microtonal intervals or non-Western scales planned?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [January 6, 2024, 10:52pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/7 "2024-01-06T22:52:42Z")

</div>

Is there a comparable package in another language that you drew inspiration from? Have you looked at e.g. [Haskore](https://wiki.haskell.org/Haskore) or some of the many [github music-theory packages](https://github.com/topics/music-theory)?

In a vacuum, it’s not obvious to me what the essential features of a music-theory package should be, and what data structures are best. e.g. why is a scale an iterator and not an indexable object? Should there be a transpose function? Chords? Time signatures?

Is the intended use case electronic composition? Analyzing music? Basic pedagogy?

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [January 6, 2024, 11:44pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/8 "2024-01-06T23:44:30Z")

</div>

Do you In the background simply use the frequency of each note to make the computations ? E.g. you may identify a minor third by the fact that the frequency ratio is 2^{3/12}

---

<div class="post-metadata">

**Author:** ![maxkapur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/maxkapur/32/21208_2.png) [@maxkapur](https://discourse.julialang.org/u/maxkapur)\
**Post date:** [January 7, 2024, 1:06am UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/9 "2024-01-07T01:06:07Z")

</div>

Interesting …! I have always thought building out a library of data structures to represent the basic building blocks of tonal theory would be a cool way to exercise a programming language’s type system, with chords and harmonic progression as a stretch goal.

Sort of like the famous [Cards.jl](https://github.com/StefanKarpinski/Cards.jl), this project shows the expressiveness of the type system even if it doesn’t have an immediate use case in mind.

> [@dpsanders](#):
>
> ```julia
> julia> scale = Scale(C[4], major_scale) 
> Scale{Pitch}(C₄, Dict{PitchClass, Interval}(C => Major 2nd, E => Minor 2nd, B => Minor 2nd, F => Major 2nd, D => Major 2nd, G => Major 2nd, A => Major 2nd)) 
> 
> ```

Looks like you are encoding each scale as dictionary mapping each `PitchClass` in the scale to the `Interval` that points to the `PitchClass` that follows it ascending order in the scale. May I ask about the motivation for this? Why not a vector (or even `SVector{PitchClass, 7}`) just giving the pitches in ascending order?

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [January 7, 2024, 9:34am UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/10 "2024-01-07T09:34:17Z")

</div>

Fantastic, thanks for sharing! Would be nice if we can get conversions between a `MIDI.Note` from MIDI.jl to a `MusicTheory.Pitch` and vice versa. Would allow even more advanced music data analysis in terms of music theory this way!

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [January 7, 2024, 9:38am UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/11 "2024-01-07T09:38:44Z")

</div>

> [@stevengj](#):
>
> Should there be a transpose function? Chords? Time signatures?
> 
> Is the intended use case electronic composition? Analyzing music? Basic pedagogy?

I can talk for MusicManipulations.jl which has transposition and some other basic “music” operations: its usage is all three of these aspects: I’ve used it to generate music, to generate educational material for learning music (e.g., generate practice drills) and I’ve used it extensively to analyze real music data recorded in the form of MIDI.jl. As far as I can tell, MusicTheory.jl can couple to all of these aspects and allow generating music drills and also analyzing real music in terms of music theory aspects and compositional aspects!

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [January 7, 2024, 10:10pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/12 "2024-01-07T22:10:36Z")

</div>

> [@stevengj](#):
>
> Is there a comparable package in another language that you drew inspiration from? Have you looked at e.g. [Haskore](https://wiki.haskell.org/Haskore) or some of the many [github music-theory packages](https://github.com/topics/music-theory)?

I deliberately chose not to look at other packages, to avoid being influenced by their choices. Now would be a good time to do so, though. I’ll add a list of relevant packages to the README. Thanks for the references; I didn’t know about these.  
There’s [abjad](https://abjad.github.io/) and [music21](https://web.mit.edu/music21/) in Python that I am aware of.

> [@stevengj](#):
>
> Are microtonal intervals or non-Western scales planned?

Unfortunately my personal knowledge about both of these is ≤ 0, so I won’t be the one to implement them. But these would be great to have if we can work out the correct data structures, yes. PRs are welcome!

> [@stevengj](#):
>
> In a vacuum, it’s not obvious to me what the essential features of a music-theory package should be, and what data structures are best. e.g. why is a scale an iterator and not an indexable object? Should there be a transpose function? Chords? Time signatures?

Agreed, the data structures are non-obvious.  
It’s a great point that scales should be indexable; I’ve added an issue for that.

For `transpose`, one thing I forgot to mention is that the package is built around _adding intervals_, e.g.

```julia
julia> C[4] + Interval(3, Major)
E[4]

```

so that makes `transpose` very easy to implement 🙂

Chords are already “implemented”, and I’ve made a start on triads. Please see the (minimal) tests and the code; help is always welcome with the docs, if anybody is good at this, of course! I haven’t been following developments regarding `Documenter.jl` or whatever the current facilities are so help with that would be great.

> [@stevengj](#):
>
> Is the intended use case electronic composition? Analyzing music? Basic pedagogy?

It’s intended to be a common language for all things music in Julia. Maybe some of it should be split out into `MusicBase.jl` or similar.

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [January 7, 2024, 10:15pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/13 "2024-01-07T22:15:08Z")

</div>

> [@lrnv](#):
>
> Do you In the background simply use the frequency of each note to make the computations ? E.g. you may identify a minor third by the fact that the frequency ratio is 2^{3/12}23/12

No, actually there’s no mention of frequencies in the package (yet).

Fortunately or unfortunately, music notation is not a direct mapping from maths. In particular, you cannot specify pitches uniquely using a single number like frequency, since e.g. `D♭` and `C♯` return to the “same note” – at least in equal temperament.  
So each pitch needs at least _two_ independent labels. In the package I have chosen a `semitone` label (numbered up from `C0`) and a `tone` label (not a particularly good name), which is the “number of pitch classes from C0”. E.g. the `tone` for `C♭` , `C♮` and `C♯` are the same number.

Currently both the semitone and tone labels are just `Int`s, but they should probably be dedicated `Semitone` and `PitchClassNumber` (or something) `struct`s.

This is actually one of the trickiest points with representing music, as far as I can see!

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [January 7, 2024, 10:15pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/14 "2024-01-07T22:15:52Z")

</div>

> [@dpsanders](#):
>
> I deliberately chose not to look at other packages, to avoid being influenced by their choices.

This has its pros and cons, but it loses the second-mover advantage of being able to distill the best features of other people’s work and avoid repeating mistakes…

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [January 7, 2024, 10:17pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/15 "2024-01-07T22:17:49Z")

</div>

> [@maxkapur](#):
>
> Looks like you are encoding each scale as dictionary mapping each `PitchClass` in the scale to the `Interval` that points to the `PitchClass` that follows it ascending order in the scale. May I ask about the motivation for this? Why not a vector (or even `SVector{PitchClass, 7}`) just giving the pitches in ascending order?

I’m using a dictionary so that it’s easier to look up “which note in the scale is the next one after `E`”. And I’m using intervals to allow iterating to the next note by adding the corresponding interval, so that I can keep going arbitrarily far in the same direction, e.g.

```julia
julia> notes = Base.Iterators.take(scale, 15) |> collect; show(notes)
Pitch[C₄, D₄, E₄, F₄, G₄, A₄, B₄, C₅, D₅, E₅, F₅, G₅, A₅, B₅, C₆]

```

But @stevengj’s suggestion to implement indexing might be a more natural solution for this, in which case we would probably want a `scale_tones` field in the `Scale` `struct` that contains the pitches in the scale as you suggest!

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [January 7, 2024, 10:18pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/16 "2024-01-07T22:18:18Z")

</div>

> _Haskell School of Music_ is a textbook about Euterpea and working with music in Haskell. It was originally started by Paul Hudak and was later finished by Donya Quick.

[https://www.euterpea.com/haskell-school-of-music/](https://www.euterpea.com/haskell-school-of-music/)

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [January 7, 2024, 10:21pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/17 "2024-01-07T22:21:13Z")

</div>

> [@Datseris](#):
>
> Fantastic, thanks for sharing! Would be nice if we can get conversions between a `MIDI.Note` from [MIDI.jl](https://juliahub.com/ui/Packages/MIDI) to a `MusicTheory.Pitch` and vice versa. Would allow even more advanced music data analysis in terms of music theory this way!

Thanks George! Yes we definitely need some good inter-operability with your great packages 🙂

---

<div class="post-metadata">

**Author:** ![KZiemian](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kziemian/32/9020_2.png) [@KZiemian](https://discourse.julialang.org/u/KZiemian)\
**Post date:** [January 7, 2024, 10:34pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/18 "2024-01-07T22:34:53Z")

</div>

You never stop impressing me.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [January 7, 2024, 10:58pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/19 "2024-01-07T22:58:21Z")

</div>

> [@dpsanders](#):
>
> Fortunately or unfortunately, music notation is not a direct mapping from maths. In particular, you cannot specify pitches uniquely using a single number like frequency, since e.g. `D♭` and `C♯` return to the “same note” – at least in equal temperament.  
> So each pitch needs at least _two_ independent labels. In the package I have chosen a `semitone` label (numbered up from `C0`) and a `tone` label (not a particularly good name), which is the “number of pitch classes from C0”. E.g. the `tone` for `C♭` , `C♮` and `C♯` are the same number.

Two options: either i have to disagree with you either i am not undertanding what is a pitch. For me, a pitch _is_ a frequency : the equal temperament western music uses nowadays is just a “set of common frequencies” that we happen to use to make music and harmonies, but there are a lot of places in the world where other standards are used. On the other hand, intervals are ratio of pitches.

> you cannot specify pitches uniquely using a single number like frequency, since e.g. `D♭` and `C♯` return to the “same note”

for me same note = same pitch = same frequency.

> So each pitch needs at least _two_ independent labels

Or an infinite number of them if you start considering `C♯♯` as different from `D♮`.

> music notation is not a direct mapping from maths

I guess the mapping from music notations to math is not a bijection, but it is still surjective. You can then exploit this property to encode stuff as math: computing an interval between two notes _is_ a simple division of frequencies. For example, would you return a different interval from `A` to `D♭` and from `A` to `C♯` ?

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [January 7, 2024, 11:04pm UTC](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444/20 "2024-01-07T23:04:51Z")

</div>

> [@lrnv](#):
>
> for me same note = same pitch = same frequency.

In your vocabulary do you have any term for the type of objects where `D♭ !== C♯` in which they are not the same?

[Next page](https://discourse.julialang.org/t/ann-announcing-musictheory-jl/108444.md?page=2)
