musa-dsl 0.30.2 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/.version +6 -0
  4. data/.yardopts +7 -0
  5. data/README.md +227 -6
  6. data/docs/README.md +83 -0
  7. data/docs/api-reference.md +86 -0
  8. data/docs/getting-started/quick-start.md +93 -0
  9. data/docs/getting-started/tutorial.md +58 -0
  10. data/docs/subsystems/core-extensions.md +316 -0
  11. data/docs/subsystems/datasets.md +465 -0
  12. data/docs/subsystems/generative.md +290 -0
  13. data/docs/subsystems/matrix.md +63 -0
  14. data/docs/subsystems/midi.md +123 -0
  15. data/docs/subsystems/music.md +233 -0
  16. data/docs/subsystems/musicxml-builder.md +264 -0
  17. data/docs/subsystems/neumas.md +71 -0
  18. data/docs/subsystems/repl.md +135 -0
  19. data/docs/subsystems/sequencer.md +98 -0
  20. data/docs/subsystems/series.md +302 -0
  21. data/docs/subsystems/transcription.md +152 -0
  22. data/docs/subsystems/transport.md +177 -0
  23. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +68 -0
  24. data/lib/musa-dsl/core-ext/arrayfy.rb +110 -0
  25. data/lib/musa-dsl/core-ext/attribute-builder.rb +91 -30
  26. data/lib/musa-dsl/core-ext/deep-copy.rb +125 -2
  27. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +78 -0
  28. data/lib/musa-dsl/core-ext/extension.rb +53 -0
  29. data/lib/musa-dsl/core-ext/hashify.rb +162 -1
  30. data/lib/musa-dsl/core-ext/inspect-nice.rb +154 -0
  31. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +117 -0
  32. data/lib/musa-dsl/core-ext/with.rb +114 -0
  33. data/lib/musa-dsl/datasets/dataset.rb +109 -0
  34. data/lib/musa-dsl/datasets/delta-d.rb +78 -0
  35. data/lib/musa-dsl/datasets/e.rb +186 -2
  36. data/lib/musa-dsl/datasets/gdv.rb +279 -2
  37. data/lib/musa-dsl/datasets/gdvd.rb +201 -0
  38. data/lib/musa-dsl/datasets/helper.rb +75 -0
  39. data/lib/musa-dsl/datasets/p.rb +177 -2
  40. data/lib/musa-dsl/datasets/packed-v.rb +91 -0
  41. data/lib/musa-dsl/datasets/pdv.rb +136 -1
  42. data/lib/musa-dsl/datasets/ps.rb +134 -4
  43. data/lib/musa-dsl/datasets/score/queriable.rb +143 -1
  44. data/lib/musa-dsl/datasets/score/render.rb +105 -1
  45. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +138 -1
  46. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +111 -0
  47. data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +200 -1
  48. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +145 -1
  49. data/lib/musa-dsl/datasets/score.rb +279 -0
  50. data/lib/musa-dsl/datasets/v.rb +88 -0
  51. data/lib/musa-dsl/generative/darwin.rb +180 -1
  52. data/lib/musa-dsl/generative/generative-grammar.rb +359 -0
  53. data/lib/musa-dsl/generative/markov.rb +133 -3
  54. data/lib/musa-dsl/generative/rules.rb +258 -4
  55. data/lib/musa-dsl/generative/variatio.rb +217 -2
  56. data/lib/musa-dsl/logger/logger.rb +267 -2
  57. data/lib/musa-dsl/matrix/matrix.rb +256 -10
  58. data/lib/musa-dsl/midi/midi-recorder.rb +108 -1
  59. data/lib/musa-dsl/midi/midi-voices.rb +265 -4
  60. data/lib/musa-dsl/music/chord-definition.rb +233 -1
  61. data/lib/musa-dsl/music/chord-definitions.rb +33 -6
  62. data/lib/musa-dsl/music/chords.rb +308 -2
  63. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +315 -0
  64. data/lib/musa-dsl/music/scales.rb +957 -40
  65. data/lib/musa-dsl/musicxml/builder/attributes.rb +483 -3
  66. data/lib/musa-dsl/musicxml/builder/backup-forward.rb +166 -1
  67. data/lib/musa-dsl/musicxml/builder/direction.rb +243 -0
  68. data/lib/musa-dsl/musicxml/builder/helper.rb +240 -0
  69. data/lib/musa-dsl/musicxml/builder/measure.rb +284 -0
  70. data/lib/musa-dsl/musicxml/builder/note-complexities.rb +324 -8
  71. data/lib/musa-dsl/musicxml/builder/note.rb +285 -0
  72. data/lib/musa-dsl/musicxml/builder/part-group.rb +108 -1
  73. data/lib/musa-dsl/musicxml/builder/part.rb +139 -0
  74. data/lib/musa-dsl/musicxml/builder/pitched-note.rb +124 -0
  75. data/lib/musa-dsl/musicxml/builder/rest.rb +93 -0
  76. data/lib/musa-dsl/musicxml/builder/score-partwise.rb +276 -0
  77. data/lib/musa-dsl/musicxml/builder/typed-text.rb +62 -1
  78. data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +83 -0
  79. data/lib/musa-dsl/neumalang/neumalang.rb +675 -0
  80. data/lib/musa-dsl/neumas/array-to-neumas.rb +149 -0
  81. data/lib/musa-dsl/neumas/neuma-decoder.rb +253 -0
  82. data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +142 -2
  83. data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +82 -0
  84. data/lib/musa-dsl/neumas/neumas.rb +67 -0
  85. data/lib/musa-dsl/neumas/string-to-neumas.rb +233 -1
  86. data/lib/musa-dsl/repl/repl.rb +550 -0
  87. data/lib/musa-dsl/sequencer/base-sequencer-implementation-every.rb +118 -2
  88. data/lib/musa-dsl/sequencer/base-sequencer-implementation-move.rb +149 -2
  89. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +296 -0
  90. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +88 -2
  91. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play.rb +161 -0
  92. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +263 -0
  93. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +173 -1
  94. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +177 -0
  95. data/lib/musa-dsl/sequencer/base-sequencer.rb +710 -10
  96. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +210 -0
  97. data/lib/musa-dsl/sequencer/timeslots.rb +79 -0
  98. data/lib/musa-dsl/series/array-to-serie.rb +37 -1
  99. data/lib/musa-dsl/series/base-series.rb +843 -5
  100. data/lib/musa-dsl/series/buffer-serie.rb +48 -0
  101. data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +41 -0
  102. data/lib/musa-dsl/series/main-serie-constructors.rb +398 -2
  103. data/lib/musa-dsl/series/main-serie-operations.rb +538 -16
  104. data/lib/musa-dsl/series/proxy-serie.rb +67 -0
  105. data/lib/musa-dsl/series/quantizer-serie.rb +45 -7
  106. data/lib/musa-dsl/series/queue-serie.rb +65 -0
  107. data/lib/musa-dsl/series/series-composer.rb +701 -0
  108. data/lib/musa-dsl/series/timed-serie.rb +473 -28
  109. data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +404 -1
  110. data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +118 -0
  111. data/lib/musa-dsl/transcription/from-gdv.rb +84 -1
  112. data/lib/musa-dsl/transcription/transcription.rb +265 -0
  113. data/lib/musa-dsl/transport/clock.rb +125 -0
  114. data/lib/musa-dsl/transport/dummy-clock.rb +89 -2
  115. data/lib/musa-dsl/transport/external-tick-clock.rb +91 -0
  116. data/lib/musa-dsl/transport/input-midi-clock.rb +133 -1
  117. data/lib/musa-dsl/transport/timer-clock.rb +183 -1
  118. data/lib/musa-dsl/transport/timer.rb +83 -0
  119. data/lib/musa-dsl/transport/transport.rb +318 -0
  120. data/lib/musa-dsl/version.rb +1 -1
  121. data/lib/musa-dsl.rb +132 -25
  122. data/musa-dsl.gemspec +12 -10
  123. metadata +87 -8
@@ -1,12 +1,145 @@
1
1
  require 'set'
2
2
 
3
3
  module Musa
4
+ # Chord construction and manipulation framework.
5
+ #
6
+ # The Chords module provides a comprehensive system for defining, creating, and
7
+ # manipulating musical chords. It supports standard chord types (triads, sevenths,
8
+ # ninths, etc.) with various qualities (major, minor, diminished, augmented, dominant).
9
+ #
10
+ # ## Architecture
11
+ #
12
+ # - **ChordDefinition**: Template defining chord structure (intervals and features)
13
+ # - **Chord**: Actual chord instance with specific root and scale context
14
+ #
15
+ # ## Basic Usage
16
+ #
17
+ # # Create chord from scale note
18
+ # scale = Scales::Scales.default_system.default_tuning.major[60]
19
+ # chord = scale.tonic.chord # C major triad
20
+ # chord = scale.tonic.chord :triad # Explicitly specify size
21
+ #
22
+ # ## Features
23
+ #
24
+ # Chords are defined by features:
25
+ #
26
+ # - **quality**: :major, :minor, :diminished, :augmented, :dominant
27
+ # - **size**: :triad, :seventh, :ninth, :eleventh, :thirteenth
28
+ #
29
+ # # Registered chord definitions.
30
+ #
31
+ # ## Triads
32
+ #
33
+ # Basic three-note chords:
34
+ #
35
+ # - **:maj** - Major triad (1-3-5): root, major third, perfect fifth
36
+ # - **:min** - Minor triad (1-♭3-5): root, minor third, perfect fifth
37
+ # - **:dim** - Diminished triad (1-♭3-♭5): root, minor third, diminished fifth
38
+ # - **:aug** - Augmented triad (1-3-♯5): root, major third, augmented fifth
39
+ #
40
+ # ## Seventh Chords
41
+ #
42
+ # Four-note chords with added seventh:
43
+ #
44
+ # - **:maj7** - Major seventh (1-3-5-7): major triad + major seventh
45
+ # - **:min7** - Minor seventh (1-♭3-5-♭7): minor triad + minor seventh
46
+ # - **:dom7** - Dominant seventh (1-3-5-♭7): major triad + minor seventh
47
+ #
48
+ # ## Extended Chords
49
+ #
50
+ # Chords with ninths, elevenths, and thirteenths:
51
+ #
52
+ # - **:maj9, :min9, :dom9** - Ninth chords
53
+ # - **:maj11, :min11** - Eleventh chords
54
+ # - **:maj13, :min13** - Thirteenth chords
55
+ #
56
+ # @see ChordDefinition Chord template/definition
57
+ # @see Chord Instantiated chord
4
58
  module Chords
59
+ # Chord template defining structure and features.
60
+ #
61
+ # ChordDefinition is a template that specifies the intervals and characteristics
62
+ # of a chord type. It's defined once and used to create many chord instances.
63
+ #
64
+ # ## Components
65
+ #
66
+ # - **Name**: Unique identifier (:maj, :min, :dom7, etc.)
67
+ # - **Offsets**: Semitone intervals from root ({ root: 0, third: 4, fifth: 7 })
68
+ # - **Features**: Characteristics (quality: :major, size: :triad)
69
+ #
70
+ # ## Registration
71
+ #
72
+ # Chord definitions are registered globally:
73
+ #
74
+ # ChordDefinition.register :maj,
75
+ # quality: :major,
76
+ # size: :triad,
77
+ # offsets: { root: 0, third: 4, fifth: 7 }
78
+ #
79
+ # ## Finding Definitions
80
+ #
81
+ # **By name**:
82
+ #
83
+ # ChordDefinition[:maj] # => <ChordDefinition :maj>
84
+ #
85
+ # **By features**:
86
+ #
87
+ # ChordDefinition.find_by_features(quality: :major, size: :triad)
88
+ # # => [<ChordDefinition :maj>]
89
+ #
90
+ # **By pitches**:
91
+ #
92
+ # ChordDefinition.find_by_pitches([60, 64, 67]) # C E G
93
+ # # => <ChordDefinition :maj>
94
+ #
95
+ # @example Defining a major triad
96
+ # ChordDefinition.register :maj,
97
+ # quality: :major,
98
+ # size: :triad,
99
+ # offsets: { root: 0, third: 4, fifth: 7 }
100
+ #
101
+ # @example Defining a dominant seventh
102
+ # ChordDefinition.register :dom7,
103
+ # quality: :dominant,
104
+ # size: :seventh,
105
+ # offsets: { root: 0, third: 4, fifth: 7, seventh: 10 }
106
+ #
107
+ # @see Chord Instantiated chord using this definition
108
+ # @see chord-definitions.rb Standard chord definitions
5
109
  class ChordDefinition
110
+ # Retrieves a registered chord definition by name.
111
+ #
112
+ # @param name [Symbol] chord definition name
113
+ # @return [ChordDefinition, nil] definition or nil if not found
114
+ #
115
+ # @example
116
+ # ChordDefinition[:maj] # => <ChordDefinition :maj>
117
+ # ChordDefinition[:min7] # => <ChordDefinition :min7>
6
118
  def self.[](name)
7
119
  @definitions[name]
8
120
  end
9
121
 
122
+ # Registers a new chord definition.
123
+ #
124
+ # Creates and registers a chord definition with specified intervals and features.
125
+ # The definition becomes available globally for chord creation.
126
+ #
127
+ # @param name [Symbol] unique chord identifier
128
+ # @param offsets [Hash{Symbol => Integer}] semitone intervals from root
129
+ # @param features [Hash] chord characteristics (quality, size, etc.)
130
+ # @return [self]
131
+ #
132
+ # @example Major triad
133
+ # ChordDefinition.register :maj,
134
+ # quality: :major,
135
+ # size: :triad,
136
+ # offsets: { root: 0, third: 4, fifth: 7 }
137
+ #
138
+ # @example Minor seventh
139
+ # ChordDefinition.register :min7,
140
+ # quality: :minor,
141
+ # size: :seventh,
142
+ # offsets: { root: 0, third: 3, fifth: 7, seventh: 11 }
10
143
  def self.register(name, offsets:, **features)
11
144
  definition = ChordDefinition.new(name, offsets: offsets, **features)
12
145
 
@@ -22,10 +155,28 @@ module Musa
22
155
  self
23
156
  end
24
157
 
158
+ # Finds chord definition matching a set of pitches.
159
+ #
160
+ # Identifies chord by comparing pitch intervals, accounting for octave reduction.
161
+ #
162
+ # @param pitches [Array<Integer>] MIDI pitch numbers
163
+ # @return [ChordDefinition, nil] matching definition or nil
164
+ #
165
+ # @example
166
+ # ChordDefinition.find_by_pitches([60, 64, 67]) # => :maj
25
167
  def self.find_by_pitches(pitches)
26
168
  @definitions.values.find { |d| d.matches(pitches) }
27
169
  end
28
170
 
171
+ # Converts feature values to feature hash.
172
+ #
173
+ # @param values [Array<Symbol>] feature values
174
+ # @param hash [Hash] feature key-value pairs
175
+ # @return [Hash] combined features
176
+ #
177
+ # @example
178
+ # features_from([:major, :triad])
179
+ # # => { quality: :major, size: :triad }
29
180
  def self.features_from(values = nil, hash = nil)
30
181
  values ||= []
31
182
  hash ||= {}
@@ -36,23 +187,49 @@ module Musa
36
187
  features
37
188
  end
38
189
 
190
+ # Finds definitions matching specified features.
191
+ #
192
+ # @param values [Array<Symbol>] feature values
193
+ # @param hash [Hash] feature key-value pairs
194
+ # @return [Array<ChordDefinition>] matching definitions
195
+ #
196
+ # @example
197
+ # find_by_features(quality: :major, size: :triad)
198
+ # # => [<ChordDefinition :maj>]
39
199
  def self.find_by_features(*values, **hash)
40
200
  features = features_from(values, hash)
41
201
  @definitions.values.select { |d| features <= d.features }
42
202
  end
43
203
 
204
+ # Returns feature key for a feature value.
205
+ #
206
+ # @param feature_value [Symbol] feature value
207
+ # @return [Symbol] feature key
44
208
  def self.feature_key_of(feature_value)
45
209
  @features_by_value[feature_value]
46
210
  end
47
211
 
212
+ # Returns all registered feature values.
213
+ #
214
+ # @return [Array<Symbol>] feature values
48
215
  def self.feature_values
49
216
  @features_by_value.keys
50
217
  end
51
218
 
219
+ # Returns all registered feature keys.
220
+ #
221
+ # @return [Set<Symbol>] feature keys
52
222
  def self.feature_keys
53
223
  @feature_keys
54
224
  end
55
225
 
226
+ # Creates a chord definition.
227
+ #
228
+ # @param name [Symbol] chord name
229
+ # @param offsets [Hash{Symbol => Integer}] semitone offsets
230
+ # @param features [Hash] chord features
231
+ #
232
+ # @api private
56
233
  def initialize(name, offsets:, **features)
57
234
  @name = name.freeze
58
235
  @features = features.transform_values(&:dup).transform_values(&:freeze).freeze
@@ -61,16 +238,52 @@ module Musa
61
238
  freeze
62
239
  end
63
240
 
64
- attr_reader :name, :features, :pitch_offsets, :pitch_names
241
+ # Chord name.
242
+ # @return [Symbol]
243
+ attr_reader :name
65
244
 
245
+ # Chord features (quality, size, etc.).
246
+ # @return [Hash{Symbol => Symbol}]
247
+ attr_reader :features
248
+
249
+ # Semitone offsets by position name.
250
+ # @return [Hash{Symbol => Integer}]
251
+ attr_reader :pitch_offsets
252
+
253
+ # Position names by semitone offset.
254
+ # @return [Hash{Integer => Symbol}]
255
+ attr_reader :pitch_names
256
+
257
+ # Calculates chord pitches from root pitch.
258
+ #
259
+ # @param root_pitch [Integer] MIDI root pitch
260
+ # @return [Array<Integer>] chord pitches
261
+ #
262
+ # @example
263
+ # chord_def.pitches(60) # => [60, 64, 67] for C major
66
264
  def pitches(root_pitch)
67
265
  @pitch_offsets.values.collect { |offset| root_pitch + offset }
68
266
  end
69
267
 
268
+ # Checks if chord fits within a scale.
269
+ #
270
+ # @param scale [Scale] scale to check against
271
+ # @param chord_root_pitch [Integer] chord root pitch
272
+ # @return [Boolean] true if all chord notes are in scale
273
+ #
274
+ # @example
275
+ # maj_def.in_scale?(c_major, chord_root_pitch: 60) # => true
70
276
  def in_scale?(scale, chord_root_pitch:)
71
277
  !pitches(chord_root_pitch).find { |chord_pitch| scale.note_of_pitch(chord_pitch).nil? }
72
278
  end
73
279
 
280
+ # Maps elements to named chord positions.
281
+ #
282
+ # @param elements_or_pitches [Array] elements to map
283
+ # @yield [element] block to extract pitch from element
284
+ # @return [Hash{Symbol => Array}] position names to elements
285
+ #
286
+ # @api private
74
287
  def named_pitches(elements_or_pitches, &block)
75
288
  pitches = elements_or_pitches.collect do |element_or_pitch|
76
289
  [if block_given?
@@ -93,6 +306,16 @@ module Musa
93
306
  end.to_h
94
307
  end
95
308
 
309
+ # Checks if pitches match this chord definition.
310
+ #
311
+ # Compares octave-reduced pitch sets to determine if they form this chord.
312
+ #
313
+ # @param pitches [Array<Integer>] MIDI pitches to check
314
+ # @return [Boolean] true if pitches match this chord
315
+ #
316
+ # @example
317
+ # maj_def.matches([60, 64, 67]) # => true (C major)
318
+ # maj_def.matches([60, 63, 67]) # => false (C minor)
96
319
  def matches(pitches)
97
320
  reduced_pitches = octave_reduce(pitches).uniq
98
321
 
@@ -101,6 +324,9 @@ module Musa
101
324
  end
102
325
  end
103
326
 
327
+ # Returns string representation.
328
+ #
329
+ # @return [String]
104
330
  def inspect
105
331
  "<ChordDefinition: name = #{@name} features = #{@features} pitch_offsets = #{@pitch_offsets}>"
106
332
  end
@@ -109,6 +335,12 @@ module Musa
109
335
 
110
336
  private
111
337
 
338
+ # Reduces pitches to within one octave (0-11).
339
+ #
340
+ # @param pitches [Array<Integer>] MIDI pitches
341
+ # @return [Array<Integer>] octave-reduced pitches
342
+ #
343
+ # @api private
112
344
  def octave_reduce(pitches)
113
345
  pitches.collect { |p| p % 12 }
114
346
  end
@@ -2,22 +2,49 @@ require_relative 'chord-definition'
2
2
 
3
3
  # TODO trasladar los acordes de https://en.wikipedia.org/wiki/Chord_notation
4
4
 
5
+ # TRIADS
6
+ # Major triad: C-E-G (0-4-7 semitones)
5
7
  Musa::Chords::ChordDefinition.register :maj, quality: :major, size: :triad, offsets: { root: 0, third: 4, fifth: 7 }
8
+
9
+ # Minor triad: C-Eb-G (0-3-7 semitones)
6
10
  Musa::Chords::ChordDefinition.register :min, quality: :minor, size: :triad, offsets: { root: 0, third: 3, fifth: 7 }
7
- Musa::Chords::ChordDefinition.register :dim, quality: :diminished, size: :triad, offsets: { root: 0, third: 3, fifth: 3 }
11
+
12
+ # Diminished triad: C-Eb-Gb (0-3-6 semitones)
13
+ Musa::Chords::ChordDefinition.register :dim, quality: :diminished, size: :triad, offsets: { root: 0, third: 3, fifth: 6 }
14
+
15
+ # Augmented triad: C-E-G# (0-4-8 semitones)
8
16
  Musa::Chords::ChordDefinition.register :aug, quality: :augmented, size: :triad, offsets: { root: 0, third: 4, fifth: 8 }
9
17
 
18
+ # SEVENTH CHORDS
19
+ # Major seventh: C-E-G-B (0-4-7-11 semitones)
10
20
  Musa::Chords::ChordDefinition.register :maj7, quality: :major, size: :seventh, offsets: { root: 0, third: 4, fifth: 7, seventh: 11 }
11
- Musa::Chords::ChordDefinition.register :min7, quality: :minor, size: :seventh, offsets: { root: 0, third: 3, fifth: 7, seventh: 11 }
12
21
 
22
+ # Minor seventh: C-Eb-G-Bb (0-3-7-10 semitones)
23
+ Musa::Chords::ChordDefinition.register :min7, quality: :minor, size: :seventh, offsets: { root: 0, third: 3, fifth: 7, seventh: 10 }
24
+
25
+ # Dominant seventh: C-E-G-Bb (0-4-7-10 semitones)
13
26
  Musa::Chords::ChordDefinition.register :dom7, quality: :dominant, size: :seventh, offsets: { root: 0, third: 4, fifth: 7, seventh: 10 }
14
27
 
28
+ # NINTH CHORDS
29
+ # Major ninth: C-E-G-B-D (0-4-7-11-14 semitones)
15
30
  Musa::Chords::ChordDefinition.register :maj9, quality: :major, size: :ninth, offsets: { root: 0, third: 4, fifth: 7, seventh: 11, ninth: 14 }
16
- Musa::Chords::ChordDefinition.register :min9, quality: :minor, size: :ninth, offsets: { root: 0, third: 3, fifth: 7, seventh: 11, ninth: 14 }
31
+
32
+ # Minor ninth: C-Eb-G-Bb-D (0-3-7-10-14 semitones) - NOTE: Changed seventh from 11 to 10
33
+ Musa::Chords::ChordDefinition.register :min9, quality: :minor, size: :ninth, offsets: { root: 0, third: 3, fifth: 7, seventh: 10, ninth: 14 }
34
+
35
+ # Dominant ninth: C-E-G-Bb-D (0-4-7-10-14 semitones)
17
36
  Musa::Chords::ChordDefinition.register :dom9, quality: :dominant, size: :ninth, offsets: { root: 0, third: 4, fifth: 7, seventh: 10, ninth: 14 }
18
37
 
38
+ # ELEVENTH CHORDS
39
+ # Major eleventh: C-E-G-B-D-F (0-4-7-11-14-17 semitones)
19
40
  Musa::Chords::ChordDefinition.register :maj11, quality: :major, size: :eleventh, offsets: { root: 0, third: 4, fifth: 7, seventh: 11, ninth: 14, eleventh: 17 }
20
- Musa::Chords::ChordDefinition.register :min11, quality: :minor, size: :eleventh, offsets: { root: 0, third: 3, fifth: 7, seventh: 11, ninth: 14, eleventh: 17 }
21
41
 
22
- Musa::Chords::ChordDefinition.register :maj13, quality: :major, size: :eleventh, offsets: { root: 0, third: 4, fifth: 7, seventh: 11, ninth: 14, eleventh: 17 }
23
- Musa::Chords::ChordDefinition.register :min13, quality: :minor, size: :eleventh, offsets: { root: 0, third: 3, fifth: 7, seventh: 11, ninth: 14, eleventh: 17 }
42
+ # Minor eleventh: C-Eb-G-Bb-D-F (0-3-7-10-14-17 semitones) - NOTE: Changed seventh from 11 to 10
43
+ Musa::Chords::ChordDefinition.register :min11, quality: :minor, size: :eleventh, offsets: { root: 0, third: 3, fifth: 7, seventh: 10, ninth: 14, eleventh: 17 }
44
+
45
+ # THIRTEENTH CHORDS
46
+ # Major thirteenth: C-E-G-B-D-F-A (0-4-7-11-14-17-21 semitones)
47
+ Musa::Chords::ChordDefinition.register :maj13, quality: :major, size: :thirteenth, offsets: { root: 0, third: 4, fifth: 7, seventh: 11, ninth: 14, eleventh: 17, thirteenth: 21 }
48
+
49
+ # Minor thirteenth: C-Eb-G-Bb-D-F-A (0-3-7-10-14-17-21 semitones) - NOTE: Changed seventh from 11 to 10
50
+ Musa::Chords::ChordDefinition.register :min13, quality: :minor, size: :thirteenth, offsets: { root: 0, third: 3, fifth: 7, seventh: 10, ninth: 14, eleventh: 17, thirteenth: 21 }