AudioKit / Tonic

Swift library for music theory
https://www.audiokit.io/Tonic/
MIT License
154 stars 21 forks source link

Query the notes of Key with correct octave information #25

Open SebastianBoldt opened 10 months ago

SebastianBoldt commented 10 months ago

Description

It may be incorrect, but is extracting the correct notes with their respective octaves from a Key object impossible?

I tried to obtain the correct notes and pitches for a Key by mapping all the notes from the noteSet, since it was the only property available in the chord object. I used the following code:

key.noteSet.array.map {
     var note = $0
     note.octave = 0
     return note.pitch 
}

Unfortunately, the noteClasses do not contain the octave information, making it impossible for me to obtain the correct pitches for a specific Key.

po Key.init(root: .init(.D, accidental: .natural), scale: .major).noteSet.array
▿ 7 elements
  ▿ 0 : C♯4
    ▿ noteClass : C♯
      - letter : Tonic.Letter.C
      - accidental : ♯
    - octave : 4
  ▿ 1 : D4
    ▿ noteClass : D
      - letter : Tonic.Letter.D
      - accidental : 
    - octave : 4
  ▿ 2 : E4
    ▿ noteClass : E
      - letter : Tonic.Letter.E
      - accidental : 
    - octave : 4
  ▿ 3 : F♯4
    ▿ noteClass : F♯
      - letter : Tonic.Letter.F
      - accidental : ♯
    - octave : 4
  ▿ 4 : G4
    ▿ noteClass : G
      - letter : Tonic.Letter.G
      - accidental : 
    - octave : 4
  ▿ 5 : A4
    ▿ noteClass : A
      - letter : Tonic.Letter.A
      - accidental : 
    - octave : 4
  ▿ 6 : B4
    ▿ noteClass : B
      - letter : Tonic.Letter.B
      - accidental : 
    - octave : 4

Proposed Solution

I would like to be able to do something like this:

key.pitches(octave: 1)

or maybe something like this:

key.notes(octave: 1) 

So having access to notes with the correct octaves would be awesome

In this code snippet, I am increasing the octave for all notes that are lower than the pitch of the root note. Please note that I am not entirely sure if this approach will work for all possible Scale Types, but at first glance, it appears to be a promising solution.

extension Key {
    func notes(octave: Int) -> [Note] {
        var orderedNotes: [Note] = []

        for note in noteSet.array {
            let shift = note.noteClass.canonicalNote.pitch < root.canonicalNote.pitch
            let shiftedNote = Note(note.letter, accidental: note.accidental, octave: shift ? octave + 1 : octave)
            orderedNotes.append(shiftedNote)
        }

        return orderedNotes.sorted()
    }
}

Describe Alternatives You've Considered

No alternatives considered

Additional Context

No response

aure commented 9 months ago

Happy to add this if you would like to write a test and make a pull request.