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
-
.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.
-
.get(name) ⇒ ChordDefinition?
(also: [])
Retrieves a registered chord definition by name.
-
.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.
244 245 246 247 248 249 250 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 244 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.).
258 259 260 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 258 def features @features end |
#name ⇒ Symbol (readonly)
Chord name.
254 255 256 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 254 def name @name end |
#pitch_names ⇒ Hash{Integer => Symbol} (readonly)
Position names by semitone offset.
266 267 268 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 266 def pitch_names @pitch_names end |
#pitch_offsets ⇒ Hash{Symbol => Integer} (readonly)
Semitone offsets by position name.
262 263 264 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 262 def pitch_offsets @pitch_offsets end |
Class Method Details
.feature_key_of(feature_value) ⇒ Symbol
Returns feature key for a feature value.
219 220 221 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 219 def self.feature_key_of(feature_value) @features_by_value[feature_value] end |
.feature_keys ⇒ Set<Symbol>
Returns all registered feature keys.
233 234 235 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 233 def self.feature_keys @feature_keys end |
.feature_values ⇒ Array<Symbol>
Returns all registered feature values.
226 227 228 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 226 def self.feature_values @features_by_value.keys end |
.features_from(values = nil, hash = nil) ⇒ Hash
Converts feature values to feature hash.
191 192 193 194 195 196 197 198 199 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 191 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.
210 211 212 213 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 210 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.
178 179 180 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 178 def self.find_by_pitches(pitches) @definitions.values.find { |d| d.matches(pitches) } end |
.get(name) ⇒ ChordDefinition? Also known as: []
Retrieves a registered chord definition by name.
121 122 123 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 121 def self.get(name) @definitions[name] 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.
150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 150 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.each_key { |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.
287 288 289 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 287 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.
341 342 343 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 341 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.
330 331 332 333 334 335 336 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 330 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.
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 298 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.
275 276 277 |
# File 'lib/musa-dsl/music/chord-definition.rb', line 275 def pitches(root_pitch) @pitch_offsets.values.collect { |offset| root_pitch + offset } end |