staff-rs / staff

Music theory and score rendering library with midi, notes, chords, scales, and more.
https://staff-rs.github.io
MIT License
258 stars 11 forks source link

`Interval` is not well-suited for diatonic transposition. #20

Open vortexofdoom opened 8 months ago

vortexofdoom commented 8 months ago

So I'm working on a counterpoint "engine" of sorts and I'm finding that the way intervals (and by extension, scales) are implemented is making it difficult to do certain things. Treating intervals differently depending on which scale degree they're built on is not a terribly intuitive process when they are defined purely in terms of semitones. And a 5th below is not always the same number of semitones as a 5th above.

Given that all of this is incredibly useful for notation (5ths are always the same distance on the staff whether they're augmented, diminished, or perfect, and there will be commonalities in how to handle them) I think there's a case to be made for building IntervalKind and IntervalQuality enums, then making an Interval struct that included those, as well as octave offsets:

enum IntervalKind {
    Unison,
    Second,
    Third,
    Fourth,
    Fifth,
    Sixth,
    Seventh,
}

enum IntervalQuality {
    Diminished,
    Minor,
    Perfect,
    Major,
    Augmented,
}

struct Interval {
    kind: IntervalKind,
    quality: IntervalQuality,
    octaves: u8,
}

These could still translate to semitones, but I also think that the intervals as they stand should probably be i8 instead of u8, reckoning intervals from the lower and higher note can be very useful.