Class: Musa::Chords::ChordDefinition
- Defined in:
- lib/musa-dsl/music/chord-definition.rb
Overview
Chord template defining structure and features.
ChordDefinition is a template that specifies the intervals and characteristics of a chord type. It's defined once and used to create many chord instances.
Components
- Name: Unique identifier (:maj, :min, :dom7, etc.)
- Offsets: Semitone intervals from root ({ root: 0, third: 4, fifth: 7 })
- Features: Characteristics (quality: :major, size: :triad)
Registration
Chord definitions are registered globally:
ChordDefinition.register :maj,
quality: :major,
size: :triad,
offsets: { root: 0, third: 4, fifth: 7 }
Finding Definitions
By name:
ChordDefinition[:maj] # => <ChordDefinition :maj>
By features:
ChordDefinition.find_by_features(quality: :major, size: :triad)
# => [<ChordDefinition :maj>]
By pitches:
ChordDefinition.find_by_pitches([60, 64, 67]) # C E G
# => <ChordDefinition :maj>
Instance Attribute Summary collapse
-
#features ⇒ Hash{Symbol => Symbol}
readonly
Chord features (quality, size, etc.).
-
#name ⇒ Symbol
readonly
Chord name.
-
#pitch_names ⇒ Hash{Integer => Symbol}
readonly
Position names by semitone offset.
-
#pitch_offsets ⇒ Hash{Symbol => Integer}
readonly
Semitone offsets by position name.
Class Method Summary collapse
-
.[](name) ⇒ ChordDefinition?
Retrieves a registered chord definition by name.
-
.feature_key_of(feature_value) ⇒ Symbol
Returns feature key for a feature value.
-
.feature_keys ⇒ Set<Symbol>
Returns all registered feature keys.
-
.feature_values ⇒ Array<Symbol>
Returns all registered feature values.
-
.features_from(values = nil, hash = nil) ⇒ Hash
Converts feature values to feature hash.
-
.find_by_features(*values, **hash) ⇒ Array<ChordDefinition>
Finds definitions matching specified features.
-
.find_by_pitches(pitches) ⇒ ChordDefinition?
Finds chord definition matching a set of pitches.
-
.register(name, offsets:, **features) ⇒ self
Registers a new chord definition.
Instance Method Summary collapse
-
#in_scale?(scale, chord_root_pitch:) ⇒ Boolean
Checks if chord fits within a scale.
-
#initialize(name, offsets:, **features) ⇒ ChordDefinition
constructor
private
Creates a chord definition.
-
#inspect ⇒ String
(also: #to_s)
Returns string representation.
-
#matches(pitches) ⇒ Boolean
Checks if pitches match this chord definition.
-
#named_pitches(elements_or_pitches) {|element| ... } ⇒ Hash{Symbol => Array}
private
Maps elements to named chord positions.
-
#pitches(root_pitch) ⇒ Array<Integer>
Calculates chord pitches from root pitch.
Constructor Details
#initialize(name, offsets:, **features) ⇒ ChordDefinition
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Creates a chord definition.
233 234 235 236 237 238 239 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 233 def initialize(name, offsets:, **features) @name = name.freeze @features = features.transform_values(&:dup).transform_values(&:freeze).freeze @pitch_offsets = offsets.dup.freeze @pitch_names = offsets.collect { |k, v| [v, k] }.to_h.freeze freeze end |
Instance Attribute Details
#features ⇒ Hash{Symbol => Symbol} (readonly)
Chord features (quality, size, etc.).
247 248 249 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 247 def features @features end |
#name ⇒ Symbol (readonly)
Chord name.
243 244 245 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 243 def name @name end |
#pitch_names ⇒ Hash{Integer => Symbol} (readonly)
Position names by semitone offset.
255 256 257 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 255 def pitch_names @pitch_names end |
#pitch_offsets ⇒ Hash{Symbol => Integer} (readonly)
Semitone offsets by position name.
251 252 253 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 251 def pitch_offsets @pitch_offsets end |
Class Method Details
.[](name) ⇒ ChordDefinition?
Retrieves a registered chord definition by name.
118 119 120 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 118 def self.[](name) @definitions[name] end |
.feature_key_of(feature_value) ⇒ Symbol
Returns feature key for a feature value.
208 209 210 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 208 def self.feature_key_of(feature_value) @features_by_value[feature_value] end |
.feature_keys ⇒ Set<Symbol>
Returns all registered feature keys.
222 223 224 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 222 def self.feature_keys @feature_keys end |
.feature_values ⇒ Array<Symbol>
Returns all registered feature values.
215 216 217 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 215 def self.feature_values @features_by_value.keys end |
.features_from(values = nil, hash = nil) ⇒ Hash
Converts feature values to feature hash.
180 181 182 183 184 185 186 187 188 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 180 def self.features_from(values = nil, hash = nil) values ||= [] hash ||= {} features = hash.dup values.each { |v| features[@features_by_value[v]] = v } features end |
.find_by_features(*values, **hash) ⇒ Array<ChordDefinition>
Finds definitions matching specified features.
199 200 201 202 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 199 def self.find_by_features(*values, **hash) features = features_from(values, hash) @definitions.values.select { |d| features <= d.features } end |
.find_by_pitches(pitches) ⇒ ChordDefinition?
Finds chord definition matching a set of pitches.
Identifies chord by comparing pitch intervals, accounting for octave reduction.
167 168 169 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 167 def self.find_by_pitches(pitches) @definitions.values.find { |d| d.matches(pitches) } end |
.register(name, offsets:, **features) ⇒ self
Registers a new chord definition.
Creates and registers a chord definition with specified intervals and features. The definition becomes available globally for chord creation.
143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 143 def self.register(name, offsets:, **features) definition = ChordDefinition.new(name, offsets: offsets, **features) @definitions ||= {} @definitions[definition.name] = definition @features_by_value ||= {} definition.features.each { |k, v| @features_by_value[v] = k } @feature_keys ||= Set[] features.keys.each { |feature_name| @feature_keys << feature_name } self end |
Instance Method Details
#in_scale?(scale, chord_root_pitch:) ⇒ Boolean
Checks if chord fits within a scale.
276 277 278 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 276 def in_scale?(scale, chord_root_pitch:) !pitches(chord_root_pitch).find { |chord_pitch| scale.note_of_pitch(chord_pitch).nil? } end |
#inspect ⇒ String Also known as: to_s
Returns string representation.
330 331 332 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 330 def inspect "<ChordDefinition: name = #{@name} features = #{@features} pitch_offsets = #{@pitch_offsets}>" end |
#matches(pitches) ⇒ Boolean
Checks if pitches match this chord definition.
Compares octave-reduced pitch sets to determine if they form this chord.
319 320 321 322 323 324 325 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 319 def matches(pitches) reduced_pitches = octave_reduce(pitches).uniq !!reduced_pitches.find do |candidate_root_pitch| reduced_pitches.sort == octave_reduce(pitches(candidate_root_pitch)).uniq.sort end end |
#named_pitches(elements_or_pitches) {|element| ... } ⇒ Hash{Symbol => Array}
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Maps elements to named chord positions.
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 287 def named_pitches(elements_or_pitches, &block) pitches = elements_or_pitches.collect do |element_or_pitch| [if block_given? yield element_or_pitch else element_or_pitch end, element_or_pitch] end.to_h root_pitch = pitches.keys.find do |candidate_root_pitch| candidate_pitches = pitches.keys.collect { |p| p - candidate_root_pitch } octave_reduce(candidate_pitches).uniq == octave_reduce(@pitch_offsets.values).uniq end # TODO: OJO: problema con las notas duplicadas, con la identificación de inversiones y con las notas a distancias de más de una octava pitches.collect do |pitch, element| [@pitch_names[pitch - root_pitch], [element]] end.to_h end |
#pitches(root_pitch) ⇒ Array<Integer>
Calculates chord pitches from root pitch.
264 265 266 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 264 def pitches(root_pitch) @pitch_offsets.values.collect { |offset| root_pitch + offset } end |