JuliaMusic / MusicTheory.jl

Music theory in Julia
MIT License
46 stars 1 forks source link

Beginner interval question #25

Open theogf opened 3 months ago

theogf commented 3 months ago

I am a novice in music theory but I would like to create new scales. Since I don't know how to create intervals I tried to revert engineer it: I googled the Major 7th scale for C: C, E, G, and B. And tried to build the scale out of it:

intervals = [
    Interval(MusicTheory.C[4], MusicTheory.E[4]),
    Interval(MusicTheory.E[4], MusicTheory.G[4]),
    Interval(MusicTheory.G[4], MusicTheory.B[5]),
    Interval(MusicTheory.B[5], MusicTheory.C[5]),
]
4-element Vector{Interval}:
 Major 3rd
 Minor 3rd
 Major 10th
 Major 7th

However sum(intervals) fails due to

ERROR: KeyError: key 9 not found
Stacktrace:
  [1] getindex(h::Dict{Int64, Int64}, key::Int64)
    @ Base ./dict.jl:498
  [2] semitone(interval::Interval)
    @ MusicTheory ~/.julia/packages/MusicTheory/onUoY/src/intervals.jl:42
  [3] +(n::PitchClass, interval::Interval)
    @ MusicTheory ~/.julia/packages/MusicTheory/onUoY/src/intervals.jl:97
  [4] +
    @ ~/.julia/packages/MusicTheory/onUoY/src/intervals.jl:108 [inlined]
  [5] +(::Pitch, ::Interval, ::Interval)
    @ Base ./operators.jl:587
  [6] +(i1::Interval, i2::Interval)
    @ MusicTheory ~/.julia/packages/MusicTheory/onUoY/src/intervals.jl:117
  [7] add_sum
    @ ./reduce.jl:24 [inlined]
  [8] _mapreduce(f::typeof(identity), op::typeof(Base.add_sum), ::IndexLinear, A::Vector{Interval})
    @ Base ./reduce.jl:443
  [9] _mapreduce_dim
    @ ./reducedim.jl:365 [inlined]
 [10] mapreduce
    @ ./reducedim.jl:357 [inlined]
 [11] _sum
    @ ./reducedim.jl:1015 [inlined]
 [12] _sum
    @ ./reducedim.jl:1014 [inlined]
 [13] sum(a::Vector{Interval})
    @ Base ./reducedim.jl:1010

Can it be due to a bug in the implementation?

dpsanders commented 3 months ago

The issue here is that it should be B[4] not B[5]:

julia> intervals = [
           Interval(MusicTheory.C[4], MusicTheory.E[4]),
           Interval(MusicTheory.E[4], MusicTheory.G[4]),
           Interval(MusicTheory.G[4], MusicTheory.B[4]),
           Interval(MusicTheory.B[4], MusicTheory.C[5]),
       ]
4-element Vector{Interval}:
 Major 3rd
 Minor 3rd
 Major 3rd
 Minor 2nd

julia> Scale(MusicTheory.C[4], intervals)
Scale{Pitch}(C₄, Dict{PitchClass, Interval}(C => Major 3rd, G => Major 3rd, B => Minor 2nd, E => Minor 3rd))

The notes in a given octave are C, D, E, F, G, A, B in that order.

BTW I wouldn't call that a scale; that's a major 7th chord:

julia> using MusicTheory.PitchNames

julia> Chord(C[4], E[4], G[4], B[4])
Chord{Pitch}(Set(Pitch[G₄, C₄, B₄, E₄]))