Class: OutroRails::ChordSeedGenerator

Inherits:
Object
  • Object
show all
Defined in:
lib/outro_rails/generators/chord_seed_generator.rb

Overview

Generates seed data for OutroRails::Chord for a given root.

Constant Summary collapse

Vocabulary =

Shorthand for the theory vocabulary used to build intervals and symbols

Theory::ChordVocabulary
ALTERED_DOMINANTS =

Alterations on dominant chords to generate

{
  '7':  [
          %i[b5],
          %i[#5],
          %i[b9],
          %i[#9],
          %i[#11],
          %i[b13],
          %i[b5 b9],
          %i[b5 #9],
          %i[#5 b9],
          %i[#5 #9],
          %i[b9 b13],
          %i[#9 b13],
          %i[b9 #11]
        ],
  '9':  [
          %i[#11],
          %i[b13]
        ],
  '13': [
          %i[b9],
          %i[#9],
          %i[#11]
        ]
}.freeze
ADDED_TONE_POLICY =

Added tones to generate { quality: { extension: [added_tone] } }

{
  major:  {
            base: %i[add2 add4 add9 add11 add13]
          },
  minor:  {
            base: %i[add2 add4 add9 add11 add13],
            '7':  %i[add11]
          }
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root_name:, root_pitch_class: nil) ⇒ ChordSeedGenerator

Parses the root note name, optionally verifying it against an expected pitch class. Raises ArgumentError when the two disagree.



55
56
57
58
59
60
61
62
63
# File 'lib/outro_rails/generators/chord_seed_generator.rb', line 55

def initialize(root_name:, root_pitch_class: nil)
  @root = Theory::NoteName.parse(root_name)

  if root_pitch_class && Integer(root_pitch_class) != @root.pitch_class
    raise ArgumentError,
          "#{root} has pitch class #{root.pitch_class}, " \
          "specified #{root_pitch_class}"
  end
end

Instance Attribute Details

#rootObject (readonly)

The parsed Theory::NoteName every generated chord is built from



51
52
53
# File 'lib/outro_rails/generators/chord_seed_generator.rb', line 51

def root
  @root
end

Instance Method Details

#chordsObject

Builds every chord row for this root: each base quality, its permitted extensions, the altered dominants, and the allowed added tones. Raises if the result contains duplicate symbols or interval sets.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/outro_rails/generators/chord_seed_generator.rb', line 78

def chords
  rows = []

  Vocabulary::QUALITIES.each do |quality, base|
    rows << build(quality, nil, [], [], base)

    Vocabulary::EXTENSIONS.each do |extension, spec|
      next unless spec[:qualities].include?(quality)

      rows << build(quality,
                    extension,
                    [],
                    [],
                    Vocabulary.merge(base, spec[:add]))
    end
  end

  ALTERED_DOMINANTS.each do |extension, alteration_sets|
    base = Vocabulary.intervals(quality: :major, extension: extension)

    alteration_sets.each do |alterations|
      rows << build(:major,
                    extension,
                    alterations,
                    [],
                    Vocabulary.apply_alterations(base, alterations))
    end
  end

  ADDED_TONE_POLICY.each do |quality, by_extension|
    by_extension.each do |extension_key, tones|
      extension = extension_key == :base ? nil : extension_key
      base = Vocabulary.intervals(quality: quality, extension: extension)

      tones.each do |tone|
        interval = Vocabulary::ADDED_TONE_INTERVALS.fetch(tone)
        pitch_classes = Vocabulary.pitch_classes(base)

        next if pitch_classes.include?(
          interval % Theory::Interval::SEMITONES_PER_OCTAVE
        )

        rows << build(
          quality,
          extension,
          [],
          [ tone ],
          (base + [interval]).sort
        )
      end
    end
  end

  assert_no_duplicates!(rows)
  rows
end

#root_nameObject

The root spelled as written, e.g. "Bb"



66
67
68
# File 'lib/outro_rails/generators/chord_seed_generator.rb', line 66

def root_name
  root.to_s
end

#root_pitch_classObject

The root's pitch class, 0-11



71
72
73
# File 'lib/outro_rails/generators/chord_seed_generator.rb', line 71

def root_pitch_class
  root.pitch_class
end

#to_yamlObject

Renders all chords as a YAML fixture fragment



136
137
138
# File 'lib/outro_rails/generators/chord_seed_generator.rb', line 136

def to_yaml
  chords.map { |chord| entry_yaml(chord) }.join("\n")
end