Skip to content

JuliaMusic/MusicTheory.jl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MusicTheory.jl

Build Status

The goal of this package is to provide a Julian interface for representing the objects and structures in ("Western") music theory (based on semitones).

Contents of the package

  • Pitches with scientific notation, e.g. C4 for middle C
  • Intervals
  • Scales
  • Notes and rests with durations
  • Chords
  • Triads

Pitches

Pitch names are exported in the MusicTheory.PitchNames submodule.

Specifying just the name of a pitch gives a PitchClass, representing all notes of that pitch, e.g.

julia> C♯
C♯

julia> typeof(C♯)
PitchClass

Indexing gives a pitch with a specific octave, e.g.

julia> C♯[4]
C♯₄

Intervals

The Interval type computes the interval between two pitches:

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

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

Scales

General scales are supported; they are specified as a sequence of intervals dividing up an octave, e.g.

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

The Scale type is a standard Julia iterator over the scale:

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₅]

Notes

Notes have a pitch and a duration, which is a rational number, e.g. 1 // 4 for a quarter note (crotchet). Rests are specified using rest, e.g.

julia> notes = [C[5] / 4, rest / 8, D[5] / 8]
3-element Vector{Note}:
 Note(C₅, 1//4)
 Note(MusicTheory.Rest(), 1//8)
 Note(D₅, 1//8)

Example

A motivating example for writing this package was to be able to do the following types of computations.

When playing the violin, it's common to have a scale in thirds: take a scale and for each scale tone, play the note two steps above it in the scale at the same time.

Question: Which combinations of half/whole steps and pairs of major/minor thirds are possible?

Answer:

julia> scale = Scale(C[4], major_scale)

julia> notes = Base.Iterators.take(scale, 10) |> collect

julia> thirds = zip(notes, notes[3:end]) |> collect

julia> thirds_intervals = Interval.(thirds)

julia> note_intervals = Interval.(zip(notes, notes[2:end]))

julia> combinations =
        [ (note_intervals[i], thirds_intervals[i], thirds_intervals[i+1])
            for i in 1:(length(thirds)-1)
        ]

julia> result = unique(combinations)
4-element Vector{Tuple{Interval, Interval, Interval}}:
 (Major 2nd, Major 3rd, Minor 3rd)
 (Major 2nd, Minor 3rd, Minor 3rd)
 (Minor 2nd, Minor 3rd, Major 3rd)
 (Major 2nd, Major 3rd, Major 3rd)

TODO

  • Play the notes
  • Print the notes in standard notation, e.g. via an interface to Lilypond
  • Interfaces with other packages

Related packages

Author

I tried not to look at other packages, either in Julia or in other languages, while writing this. Apologies for any duplication.

Copyright David P. Sanders, 2024