dn-m / Music

Structures for the creation, analysis, and performance of music in Swift
MIT License
16 stars 5 forks source link

[Pitch] Add Scale #86

Closed jsbean closed 6 years ago

jsbean commented 6 years ago

cc @bwetherfield

Add the Scale struct. Similarly to the OrderedInterval.Collection/Chord pairing here, there is an abstract form and a concrete form. In fact, the underlying structure may be identical to that of the Chord universe, but with different affordances.

struct Scale {
    let intervals: OrderedInterval.Collection
    let first: Pitch
}
bwetherfield commented 6 years ago

Similar to my comment on #85, do you want to insist that scales are monotonically increasing / decreasing in pitch? Hence

    let intervals: UnorderedInterval.Collection
    let lowest: Pitch

or even

enum Sense {
    case ascending
    case descending
}

struct Scale {
    let sense: Sense
    let first: Pitch
    let intervals: UnorderedInterval.Collection
}
jsbean commented 6 years ago

Ahh, hmm. This is interesting. I had the same feeling when writing Scale.IntervalPattern.melodicMinorAscending.

jsbean commented 6 years ago

I'd like to pivot Scale to more of an infinite, looping Sequence than a concrete array of pitches, so that it is more logically coherent to ask for the scale degree of a pitch outside of the first octave.

jsbean commented 6 years ago

But I was considering Scale more of a static collection of pitches rather than coupling the iteration direction (.ascending / .descending) to the type itself.

jsbean commented 6 years ago

The aforementioned OrderedInterval.Collection is now Scale.IntervalPattern. I think it made more sense to have unique interval patterns for Chord and Scale concepts as they do have different affordances down the line.

jsbean commented 6 years ago

Part of me wants to elevate Scale to a protocol. At some point, I would like to have things like submediant or supertonic as properties (known at compile time) of heptatonic scales. These wouldn't be applicable to one's octatonic or custom non-EDO12 mathematically generated alien scale.

jsbean commented 6 years ago

My main desire with these structures in the short term is to provide an interface for a choose-your-own-harmonic-adventure type thing, where the chords from a given scale degree can be decoupled from the concrete scale (c major, etc.).

jsbean commented 6 years ago

More ramblings: I think it'd be wise to build out a ScaleDegree structure, with different representational affordances. The ScaleDegree might have an index (0, 1 ...), and depending on the context of the Scale (major, minor, etc.) it may be represented in different ways (I or i, etc.).

Such a structure could also encapsulate the logic of representing diminished / half-diminished, aug 6, sharp-5-flat-9 extensions.

Tell me if I am wrong here: You can put a circumflex over a letter ("Î") but not a number ("ˆ1"), which is how its used in scale degree notation. Wikipedia uses images/template :o. I'm sure smufl has a code point for this, though. (edit: Or rather perhaps not!)

bwetherfield commented 6 years ago

I'd like to pivot Scale to more of an infinite, looping Sequence than a concrete array of pitches, so that it is more logically coherent to ask for the scale degree of a pitch outside of the first octave.

Would it make sense for Scale to be of the form

struct Scale {
    pitchClasses: [Pitch.Class]
}

This could be an important component of the difference between a Chord (cf. #85) and a Scale. Is a Scale an example of something more general like an (ordered) pitch-class-set, which is more a collection of pitch classes (octave-invariant)? Or is a harmonic series a kind of scale, for example - not octave-invariant ... ?

jsbean commented 6 years ago

Hmm, yes. I was thinking that, too. For now, the Scale.IntervalPattern is built upon Pitch values for the sake of simplicity (as they are most-often used within simple arithmetic (e.g., summation, addition with root)).

See #95 where Scale is now implemented as a (potentially) infinite looping Sequence.

This implementation also does not assume octave invariance. (Currently, there is a bool property: isOctaveRepeating which checks if the intervals add up to 12).

jsbean commented 6 years ago

It could be interesting to encode things like octave invariance into the types…