head_music 8.3.0 → 11.0.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 (138) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +9 -3
  3. data/CHANGELOG.md +71 -0
  4. data/CLAUDE.md +62 -25
  5. data/Gemfile +7 -1
  6. data/Gemfile.lock +91 -3
  7. data/MUSIC_THEORY.md +120 -0
  8. data/README.md +18 -0
  9. data/Rakefile +7 -2
  10. data/head_music.gemspec +1 -1
  11. data/lib/head_music/analysis/diatonic_interval.rb +29 -27
  12. data/lib/head_music/analysis/dyad.rb +229 -0
  13. data/lib/head_music/analysis/interval_consonance.rb +51 -0
  14. data/lib/head_music/analysis/melodic_interval.rb +1 -1
  15. data/lib/head_music/analysis/pitch_class_set.rb +111 -14
  16. data/lib/head_music/analysis/{pitch_set.rb → pitch_collection.rb} +11 -5
  17. data/lib/head_music/analysis/sonority.rb +50 -12
  18. data/lib/head_music/content/note.rb +1 -1
  19. data/lib/head_music/content/placement.rb +1 -1
  20. data/lib/head_music/content/position.rb +1 -1
  21. data/lib/head_music/content/voice.rb +1 -1
  22. data/lib/head_music/instruments/alternate_tuning.rb +102 -0
  23. data/lib/head_music/instruments/alternate_tunings.yml +78 -0
  24. data/lib/head_music/instruments/instrument.rb +231 -72
  25. data/lib/head_music/instruments/instrument_configuration.rb +66 -0
  26. data/lib/head_music/instruments/instrument_configuration_option.rb +38 -0
  27. data/lib/head_music/instruments/instrument_configurations.yml +288 -0
  28. data/lib/head_music/instruments/instrument_families.yml +77 -0
  29. data/lib/head_music/instruments/instrument_family.rb +15 -5
  30. data/lib/head_music/instruments/instruments.yml +795 -965
  31. data/lib/head_music/instruments/playing_technique.rb +75 -0
  32. data/lib/head_music/instruments/playing_techniques.yml +826 -0
  33. data/lib/head_music/instruments/score_order.rb +136 -0
  34. data/lib/head_music/instruments/score_orders.yml +130 -0
  35. data/lib/head_music/instruments/staff.rb +61 -1
  36. data/lib/head_music/instruments/staff_scheme.rb +6 -4
  37. data/lib/head_music/instruments/stringing.rb +115 -0
  38. data/lib/head_music/instruments/stringing_course.rb +58 -0
  39. data/lib/head_music/instruments/stringings.yml +168 -0
  40. data/lib/head_music/instruments/variant.rb +6 -1
  41. data/lib/head_music/locales/de.yml +29 -0
  42. data/lib/head_music/locales/en.yml +106 -0
  43. data/lib/head_music/locales/es.yml +29 -0
  44. data/lib/head_music/locales/fr.yml +29 -0
  45. data/lib/head_music/locales/it.yml +29 -0
  46. data/lib/head_music/locales/ru.yml +29 -0
  47. data/lib/head_music/{rudiment → notation}/musical_symbol.rb +3 -3
  48. data/lib/head_music/notation/staff_mapping.rb +70 -0
  49. data/lib/head_music/notation/staff_position.rb +62 -0
  50. data/lib/head_music/notation.rb +7 -0
  51. data/lib/head_music/rudiment/alteration.rb +34 -49
  52. data/lib/head_music/rudiment/alterations.yml +32 -0
  53. data/lib/head_music/rudiment/base.rb +9 -0
  54. data/lib/head_music/rudiment/chromatic_interval.rb +4 -7
  55. data/lib/head_music/rudiment/clef.rb +2 -2
  56. data/lib/head_music/rudiment/consonance.rb +39 -5
  57. data/lib/head_music/rudiment/diatonic_context.rb +25 -0
  58. data/lib/head_music/rudiment/key.rb +77 -0
  59. data/lib/head_music/rudiment/key_signature/enharmonic_equivalence.rb +1 -1
  60. data/lib/head_music/rudiment/key_signature.rb +21 -8
  61. data/lib/head_music/rudiment/letter_name.rb +3 -3
  62. data/lib/head_music/rudiment/meter.rb +19 -9
  63. data/lib/head_music/rudiment/mode.rb +92 -0
  64. data/lib/head_music/rudiment/note.rb +112 -0
  65. data/lib/head_music/rudiment/pitch/parser.rb +52 -0
  66. data/lib/head_music/rudiment/pitch.rb +5 -6
  67. data/lib/head_music/rudiment/pitch_class.rb +1 -1
  68. data/lib/head_music/rudiment/quality.rb +1 -1
  69. data/lib/head_music/rudiment/reference_pitch.rb +1 -1
  70. data/lib/head_music/rudiment/register.rb +4 -1
  71. data/lib/head_music/rudiment/rest.rb +36 -0
  72. data/lib/head_music/rudiment/rhythmic_element.rb +53 -0
  73. data/lib/head_music/rudiment/rhythmic_unit/parser.rb +86 -0
  74. data/lib/head_music/rudiment/rhythmic_unit.rb +13 -5
  75. data/lib/head_music/rudiment/rhythmic_units.yml +80 -0
  76. data/lib/head_music/rudiment/rhythmic_value/parser.rb +77 -0
  77. data/lib/head_music/{content → rudiment}/rhythmic_value.rb +23 -5
  78. data/lib/head_music/rudiment/scale.rb +4 -5
  79. data/lib/head_music/rudiment/scale_degree.rb +1 -1
  80. data/lib/head_music/rudiment/scale_type.rb +9 -3
  81. data/lib/head_music/rudiment/solmization.rb +1 -1
  82. data/lib/head_music/rudiment/spelling.rb +8 -4
  83. data/lib/head_music/rudiment/tempo.rb +85 -0
  84. data/lib/head_music/rudiment/tonal_context.rb +35 -0
  85. data/lib/head_music/rudiment/tuning/just_intonation.rb +0 -39
  86. data/lib/head_music/rudiment/tuning/meantone.rb +0 -39
  87. data/lib/head_music/rudiment/tuning/pythagorean.rb +0 -39
  88. data/lib/head_music/rudiment/tuning.rb +21 -1
  89. data/lib/head_music/rudiment/unpitched_note.rb +62 -0
  90. data/lib/head_music/style/guidelines/consonant_climax.rb +2 -2
  91. data/lib/head_music/style/medieval_tradition.rb +26 -0
  92. data/lib/head_music/style/modern_tradition.rb +31 -0
  93. data/lib/head_music/style/renaissance_tradition.rb +26 -0
  94. data/lib/head_music/style/tradition.rb +21 -0
  95. data/lib/head_music/time/clock_position.rb +84 -0
  96. data/lib/head_music/time/conductor.rb +264 -0
  97. data/lib/head_music/time/meter_event.rb +37 -0
  98. data/lib/head_music/time/meter_map.rb +173 -0
  99. data/lib/head_music/time/musical_position.rb +188 -0
  100. data/lib/head_music/time/smpte_timecode.rb +164 -0
  101. data/lib/head_music/time/tempo_event.rb +40 -0
  102. data/lib/head_music/time/tempo_map.rb +187 -0
  103. data/lib/head_music/time.rb +32 -0
  104. data/lib/head_music/utilities/case.rb +27 -0
  105. data/lib/head_music/utilities/hash_key.rb +34 -2
  106. data/lib/head_music/version.rb +1 -1
  107. data/lib/head_music.rb +71 -22
  108. data/user_stories/active/string-pitches.md +41 -0
  109. data/user_stories/backlog/notation-style.md +183 -0
  110. data/user_stories/backlog/organizing-content.md +80 -0
  111. data/user_stories/done/consonance-dissonance-classification.md +117 -0
  112. data/user_stories/{backlog → done}/dyad-analysis.md +6 -16
  113. data/user_stories/done/epic--score-order/PLAN.md +244 -0
  114. data/user_stories/done/expand-playing-techniques.md +38 -0
  115. data/user_stories/done/handle-time.md +7 -0
  116. data/user_stories/done/handle-time.rb +163 -0
  117. data/user_stories/done/instrument-architecture.md +238 -0
  118. data/user_stories/done/instrument-variant.md +65 -0
  119. data/user_stories/done/move-musical-symbol-to-notation.md +161 -0
  120. data/user_stories/done/move-staff-mapping-to-notation.md +158 -0
  121. data/user_stories/done/move-staff-position-to-notation.md +141 -0
  122. data/user_stories/done/notation-module-foundation.md +102 -0
  123. data/user_stories/done/percussion_set.md +260 -0
  124. data/user_stories/done/sonority-identification.md +37 -0
  125. data/user_stories/done/superclass-for-note.md +30 -0
  126. data/user_stories/epics/notation-module.md +135 -0
  127. data/user_stories/visioning/agentic-daw.md +2 -0
  128. metadata +84 -18
  129. data/TODO.md +0 -109
  130. data/check_instrument_consistency.rb +0 -0
  131. data/test_translations.rb +0 -15
  132. data/user_stories/backlog/consonance-dissonance-classification.md +0 -57
  133. data/user_stories/backlog/pitch-set-classification.md +0 -62
  134. data/user_stories/backlog/sonority-identification.md +0 -47
  135. /data/user_stories/{backlog → done/epic--score-order}/band-score-order.md +0 -0
  136. /data/user_stories/{backlog → done/epic--score-order}/chamber-ensemble-score-order.md +0 -0
  137. /data/user_stories/{backlog → done/epic--score-order}/orchestral-score-order.md +0 -0
  138. /data/user_stories/{backlog → done}/pitch-class-set-analysis.md +0 -0
@@ -0,0 +1,260 @@
1
+ # Percussion Set Staff
2
+
3
+ As a composer or arranger
4
+
5
+ I want to create percussion set or drum kit parts in a score
6
+
7
+ So that I can notate multiple unpitched percussion instruments on a single staff
8
+
9
+ ## Background
10
+
11
+ Individual percussion instruments (timpani, snare_drum, bass_drum, etc.) already exist in the codebase and use the `neutral_clef` (also known as percussion_clef). However, there's no way to represent a **percussion set** or **drum kit** where multiple unpitched instruments are notated on a single staff with each instrument assigned to a specific line or space.
12
+
13
+ This is distinct from a clef. The `neutral_clef` already exists in `HeadMusic::Rudiment::Clef`. What's needed is:
14
+ 1. A new instrument definition for percussion sets (e.g., `drum_kit`, `percussion_set`)
15
+ 2. A staff scheme that uses the `neutral_clef`
16
+ 3. A percussion mapping system that defines which instruments appear on which staff lines/spaces
17
+
18
+ ## Scenario: Create a standard drum kit staff
19
+
20
+ Given I am composing a piece with drum kit
21
+
22
+ When I create a drum_kit instrument
23
+
24
+ Then it should use the neutral_clef
25
+
26
+ And it should have a default percussion mapping for standard drum kit instruments
27
+
28
+ ## Scenario: Map percussion instruments to staff positions
29
+
30
+ Given I have a drum_kit instrument
31
+
32
+ When I request the percussion mapping
33
+
34
+ Then I should see which line or space each percussion instrument occupies
35
+
36
+ Examples:
37
+ - Crash cymbal → line 5
38
+ - Hi-hat → line 4 (or space above)
39
+ - Snare drum → line 3 (center line)
40
+ - Bass drum → line 1 (or space below)
41
+ - Floor tom → line 2
42
+
43
+ ## Scenario: Create custom percussion set configurations
44
+
45
+ Given I want to notate a non-standard percussion ensemble
46
+
47
+ When I define a custom percussion_set
48
+
49
+ Then I should be able to specify which percussion instruments map to which staff positions
50
+
51
+ And the system should use the neutral_clef for the staff
52
+
53
+ ## Technical Notes
54
+
55
+ ### Architecture
56
+
57
+ A percussion set is:
58
+ - **NOT a clef** - it uses the existing `neutral_clef`
59
+ - **An instrument** with a special staff scheme configuration
60
+ - **A mapping system** that assigns percussion instruments to staff positions
61
+
62
+ ### Proposed Implementation
63
+
64
+ Add to `lib/head_music/instruments/instruments.yml`:
65
+
66
+ ```yaml
67
+ drum_kit:
68
+ family_key: percussion_set
69
+ variants:
70
+ default:
71
+ staff_schemes:
72
+ default:
73
+ - clef: neutral_clef
74
+ percussion_mapping:
75
+ line_5: crash_cymbal
76
+ space_4: ride_cymbal
77
+ line_4: hi_hat
78
+ space_3: high_tom
79
+ line_3: snare_drum
80
+ space_2: mid_tom
81
+ line_2: floor_tom
82
+ space_1: bass_drum
83
+ line_1: bass_drum
84
+
85
+ percussion_set:
86
+ family_key: percussion_set
87
+ variants:
88
+ default:
89
+ staff_schemes:
90
+ default:
91
+ - clef: neutral_clef
92
+ ```
93
+
94
+ ### New Concepts to Implement
95
+
96
+ 1. **Percussion mapping attribute** on `HeadMusic::Instruments::Staff`
97
+ 2. **Percussion family or category** to identify instruments as unpitched/percussion
98
+ 3. **Position resolution** to determine which line/space a percussion instrument should use
99
+
100
+ ### Related Components
101
+
102
+ - `HeadMusic::Rudiment::Clef` - neutral_clef already exists (line 115-128 in clefs.yml)
103
+ - `HeadMusic::Instruments::Staff` - would need to handle percussion_mapping attribute
104
+ - `HeadMusic::Instruments::StaffScheme` - provides the staff configuration
105
+ - Individual percussion instruments (timpani, snare_drum, etc.) already exist
106
+
107
+ ## Acceptance Criteria
108
+
109
+ - Can create a drum_kit instrument
110
+ - drum_kit uses neutral_clef by default
111
+ - Can query which percussion instrument is assigned to each staff position
112
+ - Can create custom percussion_set configurations with custom mappings
113
+ - Maintains 90%+ test coverage
114
+ - Follows existing HeadMusic patterns (factory methods, YAML data-driven)
115
+
116
+ ## Implementation Plan
117
+
118
+ ### Design Decisions
119
+
120
+ Based on research and discussion:
121
+
122
+ 1. **Naming**: Use `instrument_mapping` (not `percussion_mapping`) for flexibility
123
+ 2. **Mapping Format**: Use instrument keys (strings/symbols), not objects
124
+ 3. **Validation**:
125
+ - Mapped instruments must exist
126
+ - No requirement that they be percussion instruments
127
+ - Valid positions: `line_0` through `line_6`, `space_0` through `space_5`
128
+ 4. **Flexibility**: Mappings are immutable (YAML-defined only) for now
129
+ 5. **Stem Direction**: Rendering concern, not part of infrastructure
130
+ 6. **Composite Instruments**: No special type needed - just regular instruments with `instrument_mapping`
131
+ 7. **Family**: Use `drum_kit` family (not generic `percussion_set`)
132
+
133
+ ### Standard Drum Kit Notation Mapping
134
+
135
+ Research shows there is no single universal standard, but most common convention:
136
+
137
+ ```yaml
138
+ instrument_mapping:
139
+ space_0: hi_hat_pedal # below staff
140
+ line_1: bass_drum
141
+ line_2: floor_tom
142
+ line_3: snare_drum # middle line - most consistent
143
+ line_4: mid_tom
144
+ space_4: high_tom
145
+ line_5: ride_cymbal
146
+ space_5: hi_hat # above staff
147
+ line_6: crash_cymbal # first ledger line above
148
+ ```
149
+
150
+ ### Implementation Steps
151
+
152
+ #### 1. Add New Instrument Families
153
+ To `lib/head_music/instruments/instrument_families.yml`:
154
+ - `tom_tom` family
155
+ - `hi_hat` family
156
+ - `drum_kit` family
157
+
158
+ #### 2. Add New Individual Instruments
159
+ To `lib/head_music/instruments/instruments.yml`:
160
+ - `hi_hat` (family: hi_hat)
161
+ - `hi_hat_pedal` (family: hi_hat)
162
+ - `crash_cymbal` (family: cymbal)
163
+ - `ride_cymbal` (family: cymbal)
164
+ - `high_tom` (family: tom_tom)
165
+ - `mid_tom` (family: tom_tom)
166
+ - `floor_tom` (family: tom_tom)
167
+
168
+ Each with:
169
+ - Appropriate aliases
170
+ - `family_key` reference
171
+ - Single `default` variant
172
+ - `neutral_clef` staff scheme
173
+
174
+ #### 3. Add Composite Instrument
175
+ To `lib/head_music/instruments/instruments.yml`:
176
+ - `drum_kit` (alias: `drum_set`) with standard instrument_mapping
177
+
178
+ #### 4. Enhance Staff Class
179
+ To `lib/head_music/instruments/staff.rb`:
180
+ - Add `instrument_mapping` attribute (hash)
181
+ - Add `#instrument_for_position(position_key)` method
182
+ - Add `#position_for_instrument(instrument_name)` method
183
+ - Add `#components` method (derives instruments from mapping)
184
+ - Handle parsing `instrument_mapping` from YAML
185
+ - Validate:
186
+ - Position keys match pattern (line_0-6, space_0-5)
187
+ - Referenced instruments exist
188
+
189
+ #### 5. Tests
190
+ - Specs for all new instrument families
191
+ - Specs for all new individual instruments
192
+ - Specs for `Staff#instrument_mapping` functionality
193
+ - Specs for `drum_kit` composite instrument
194
+ - Maintain 90%+ code coverage
195
+
196
+ ---
197
+
198
+ ## Refactoring Notes (Post-Implementation)
199
+
200
+ After the initial implementation, the design was refactored to better model playing techniques as a first-class concept rather than treating them as separate instruments.
201
+
202
+ ### Key Changes:
203
+
204
+ 1. **Introduced `PlayingTechnique` class**
205
+ - Playing techniques (pedal, stick, mallet, etc.) are now modeled as objects
206
+ - Includes `HeadMusic::Named` for potential future i18n support
207
+ - Common techniques defined: stick, pedal, mallet, hand, brush, rim_shot, cross_stick, open, closed, etc.
208
+
209
+ 2. **Created `StaffMapping` class** (replaces simple hash-based approach)
210
+ - Represents the mapping of an instrument + optional playing technique to a staff position
211
+ - Uses `StaffPosition` with index-based positions (even = lines, odd = spaces)
212
+ - Attributes: `staff_position`, `instrument_key`, `playing_technique_key`
213
+ - Methods: `#instrument`, `#playing_technique`, `#position_index`, `#to_s`
214
+
215
+ 3. **Removed `hi_hat_pedal` as separate instrument**
216
+ - Hi-hat pedal is now correctly modeled as a playing technique of the hi-hat instrument
217
+ - The hi-hat appears at two positions in drum_kit mapping:
218
+ - Position -1 (space below staff): hi_hat with pedal technique
219
+ - Position 9 (space above staff): hi_hat with stick technique
220
+
221
+ 4. **Updated `Staff` class API**
222
+ - `#mappings` → returns array of `StaffMapping` objects
223
+ - `#mapping_for_position(index)` → get full mapping at position
224
+ - `#instrument_for_position(index)` → get instrument at position
225
+ - `#positions_for_instrument(key)` → returns all positions (handles multiple mappings)
226
+ - `#components` → returns unique instruments
227
+
228
+ 5. **Changed YAML format** from hash to array:
229
+ ```yaml
230
+ # Old format:
231
+ instrument_mapping:
232
+ line_3: snare_drum
233
+ space_5: hi_hat
234
+
235
+ # New format:
236
+ mappings:
237
+ - staff_position: 4 # index 4 = line 3
238
+ instrument: snare_drum
239
+ - staff_position: 9 # index 9 = space above staff
240
+ instrument: hi_hat
241
+ playing_technique: stick
242
+ ```
243
+
244
+ 6. **Added comprehensive YARD documentation**
245
+ - All new classes and public methods documented
246
+ - Examples provided for common use cases
247
+
248
+ ### Benefits of Refactoring:
249
+
250
+ - **Semantic clarity**: Hi-hat pedal is a technique, not an instrument
251
+ - **Extensibility**: Easy to add new playing techniques (bow techniques for strings, breath techniques for winds, etc.)
252
+ - **Flexibility**: Instruments can appear at multiple positions with different techniques
253
+ - **Type safety**: StaffPosition validates position indices, StaffMapping provides structured access
254
+
255
+ ### Test Results:
256
+
257
+ - **1040 examples, 0 failures** ✅
258
+ - **91.54% line coverage, 84.44% branch coverage** ✅
259
+ - All existing functionality preserved
260
+ - New tests verify multiple technique mappings
@@ -0,0 +1,37 @@
1
+ # Sonority Identification
2
+
3
+ As a music theorist or composer
4
+
5
+ I want to identify and work with named sonorities
6
+
7
+ So that I can analyze and create harmonic structures
8
+
9
+ ## Scenario: Get sonority by identifier
10
+
11
+ Given I need a specific sonority
12
+
13
+ When I call Sonority.get with an identifier like "major_triad"
14
+
15
+ Then I should receive the corresponding sonority object
16
+
17
+ And it should contain the correct interval structure
18
+
19
+ ## Scenario: Generate pitch collection from sonority
20
+
21
+ Given I have a sonority identifier and a root pitch
22
+
23
+ When I call a method to generate pitches
24
+
25
+ Then I should receive the correct pitches for that sonority
26
+
27
+ And they should be in the specified inversion
28
+
29
+ ## Scenario: Access sonority from pitch collection
30
+
31
+ Given I have a PitchCollection object
32
+
33
+ When I call the sonority method
34
+
35
+ Then I should receive the corresponding Sonority object
36
+
37
+ And it should correctly identify the harmonic content
@@ -0,0 +1,30 @@
1
+ IN ORDER TO accurately model sound events
2
+ AS a developer
3
+ I WANT a clear way to group the notion of a Note (pitch + rhythmic value) and an unpitched note.
4
+
5
+ We need a hierarchy of classes
6
+
7
+ class RhythmicEvent
8
+ attr_accessor :rhythmic_value
9
+
10
+ class Note < RhythmicEvent
11
+ attr_accessor :pitch
12
+ def sounded?
13
+ true
14
+ end
15
+
16
+ class UnpitchedNote < RhythmicEvent
17
+ def sounded?
18
+ true
19
+ end
20
+
21
+ class Rest < RhythmicEvent
22
+ def sounded?
23
+ false
24
+ end
25
+
26
+
27
+ acceptance criteria
28
+ - the above class hierarchy and implementation requirements
29
+ - full test coverage
30
+ - use NotImplementedError instead of NotImplementedError in RhythmicEvent if and where appropriate.
@@ -0,0 +1,135 @@
1
+ # EPIC: Notation Module
2
+
3
+ AS a developer
4
+
5
+ I WANT to organize notation-related features in a dedicated HeadMusic::Notation module
6
+
7
+ SO THAT I can clearly separate visual representation concerns from music theory, instrument properties, and musical content
8
+
9
+ ## Vision
10
+
11
+ Music notation is about visual representation - how musical concepts appear on paper, screen, or other media. This is conceptually distinct from:
12
+ - **Music theory** (abstract concepts like pitch, interval, harmony)
13
+ - **Instrument properties** (range, transposition, acoustic characteristics)
14
+ - **Musical content** (compositions, temporal organization)
15
+
16
+ A dedicated Notation module provides a clear home for all visual representation concerns, making the codebase more organized and enabling future expansion into comprehensive music engraving capabilities.
17
+
18
+ ## Background
19
+
20
+ Currently, notation-related code is scattered across multiple modules:
21
+ - **HeadMusic::Instruments** contains `StaffPosition`, `Staff`, `StaffMapping`, and `StaffScheme`
22
+ - **HeadMusic::Rudiment** contains `Clef`, `MusicalSymbol`, and notation aspects of `Alteration` and `RhythmicUnit`
23
+ - **HeadMusic::Content** has its own minimal `Staff` class
24
+
25
+ A TODO comment in `lib/head_music/instruments/staff_position.rb:5` suggests: "consider moving to a HeadMusic::Notation module"
26
+
27
+ This scattered organization makes it unclear where new notation features should live and conflates distinct concerns.
28
+
29
+ ## Module Boundaries
30
+
31
+ ### HeadMusic::Notation (visual representation)
32
+ - Staff positions, lines, spaces, ledger lines
33
+ - Musical symbols (ASCII, Unicode, HTML entities)
34
+ - Notehead shapes and placement on staff
35
+ - Stem direction and flags
36
+ - Clef symbols and their staff placement
37
+ - Accidental symbol placement
38
+ - Future: beaming, ties, slurs, articulations, dynamics
39
+
40
+ ### HeadMusic::Rudiment (music theory)
41
+ - Abstract concepts: pitch, interval, scale, chord
42
+ - Duration concepts (without visual representation)
43
+ - Keys, meters (as musical concepts, not visual symbols)
44
+ - Core theory that notation represents visually
45
+
46
+ ### HeadMusic::Instruments (instrument properties)
47
+ - Instrument families and classification
48
+ - Pitch ranges and transposition
49
+ - Playing techniques
50
+ - Score ordering
51
+ - References to default clef (but doesn't own clef rendering)
52
+
53
+ ### HeadMusic::Content (musical content)
54
+ - Compositions, voices, bars
55
+ - Notes in context (pitch + duration + placement)
56
+ - Temporal organization
57
+ - Uses Notation for visual representation
58
+
59
+ ## Scope
60
+
61
+ ### Phase 1: Foundation & Core Moves (Current Focus)
62
+ - Establish module infrastructure
63
+ - Move `StaffPosition` from Instruments to Notation
64
+ - Move `MusicalSymbol` from Rudiment to Notation
65
+ - Move `StaffMapping` from Instruments to Notation
66
+
67
+ **User Stories:**
68
+ - [Notation Module Foundation](../backlog/notation-module-foundation.md)
69
+ - [Move StaffPosition to Notation](../backlog/move-staff-position-to-notation.md)
70
+ - [Move MusicalSymbol to Notation](../backlog/move-musical-symbol-to-notation.md)
71
+ - [Move StaffMapping to Notation](../backlog/move-staff-mapping-to-notation.md)
72
+
73
+ ### Phase 2: Extract Notation Aspects (Future)
74
+ - Create `ClefPlacement` - extract visual clef positioning from `Rudiment::Clef`
75
+ - Create `AccidentalPlacement` - extract accidental display rules from `Rudiment::Alteration`
76
+ - Create `RhythmicNotation` - extract notehead, stem, flag logic from `Rudiment::RhythmicUnit`
77
+ - Refactor `StaffScheme` to `Notation::StaffSystem`
78
+
79
+ ### Phase 3: Advanced Notation Features (Long-term Vision)
80
+ - Beaming (connecting note stems across beats)
81
+ - Stems (direction and length calculation)
82
+ - Ties (connecting same pitches across bars)
83
+ - Slurs (phrase markings)
84
+ - Articulations (staccato, accent, tenuto, etc.)
85
+ - Dynamics (forte, piano, crescendo, etc.)
86
+ - Tuplets (triplets, quintuplets, etc.)
87
+ - Barlines (single, double, repeat)
88
+ - Ornaments (trills, mordents, turns)
89
+ - Fermatas (pause markings)
90
+
91
+ ### Beyond Western Staff Notation (Future Exploration)
92
+
93
+ The Notation module could eventually support multiple notation systems:
94
+
95
+ **Traditional notation systems:**
96
+ - Western staff notation (current focus)
97
+ - Tablature (tab) - finger positions for guitar, bass, lute
98
+ - Shaped note notation - different note head shapes for scale degrees
99
+ - Drum notation - modified staff notation for percussion
100
+
101
+ **Alphanumeric and shorthand systems:**
102
+ - Lead sheet notation - melody with chord symbols
103
+ - Nashville Number System - scale degrees instead of chord names
104
+ - Roman numeral analysis - functional harmony labels
105
+ - ABC notation - text-based system for folk music
106
+ - Figured bass - Baroque-era interval shorthand
107
+
108
+ **Digital/computer formats:**
109
+ - MIDI - note events with pitch, velocity, timing
110
+ - MusicXML - XML-based interchange format
111
+ - Lilypond - text-based music engraving
112
+ - MEI (Music Encoding Initiative) - scholarly encoding
113
+
114
+ ## Success Criteria
115
+
116
+ **Module Organization:**
117
+ - Clear separation between theory (Rudiment), notation (Notation), instruments (Instruments), and content (Content)
118
+ - All visual representation concerns organized under `HeadMusic::Notation`
119
+ - Documentation clearly explains what belongs in each module
120
+
121
+ **Code Quality:**
122
+ - All moved classes maintain existing functionality
123
+ - 90%+ test coverage maintained throughout
124
+ - No breaking changes for internal usage
125
+ - All TODO comments resolved
126
+
127
+ **Extensibility:**
128
+ - Module designed for future expansion (beams, ties, dynamics, etc.)
129
+ - Support for multiple output formats (Unicode, MusicXML, SVG)
130
+ - Clear patterns established for adding new notation features
131
+
132
+ **Developer Experience:**
133
+ - Clear guidance in CLAUDE.md about where notation features belong
134
+ - Easy to find and use notation-related classes
135
+ - Logical organization that matches mental model of music notation
@@ -0,0 +1,2 @@
1
+ agent-centric multimedia scoring
2
+ (A/V DAW)
metadata CHANGED
@@ -1,29 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: head_music
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.3.0
4
+ version: 11.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Head
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-07-26 00:00:00.000000000 Z
11
+ date: 2026-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '7.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '10'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: '7.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '10'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: humanize
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -150,13 +156,12 @@ files:
150
156
  - Gemfile
151
157
  - Gemfile.lock
152
158
  - LICENSE.txt
159
+ - MUSIC_THEORY.md
153
160
  - README.md
154
161
  - Rakefile
155
- - TODO.md
156
162
  - bin/check_instrument_consistency.rb
157
163
  - bin/console
158
164
  - bin/setup
159
- - check_instrument_consistency.rb
160
165
  - head_music.gemspec
161
166
  - lib/head_music.rb
162
167
  - lib/head_music/analysis/circle.rb
@@ -166,27 +171,40 @@ files:
166
171
  - lib/head_music/analysis/diatonic_interval/parser.rb
167
172
  - lib/head_music/analysis/diatonic_interval/semitones.rb
168
173
  - lib/head_music/analysis/diatonic_interval/size.rb
174
+ - lib/head_music/analysis/dyad.rb
169
175
  - lib/head_music/analysis/harmonic_interval.rb
176
+ - lib/head_music/analysis/interval_consonance.rb
170
177
  - lib/head_music/analysis/interval_cycle.rb
171
178
  - lib/head_music/analysis/melodic_interval.rb
172
179
  - lib/head_music/analysis/motion.rb
173
180
  - lib/head_music/analysis/pitch_class_set.rb
174
- - lib/head_music/analysis/pitch_set.rb
181
+ - lib/head_music/analysis/pitch_collection.rb
175
182
  - lib/head_music/analysis/sonority.rb
176
183
  - lib/head_music/content/bar.rb
177
184
  - lib/head_music/content/composition.rb
178
185
  - lib/head_music/content/note.rb
179
186
  - lib/head_music/content/placement.rb
180
187
  - lib/head_music/content/position.rb
181
- - lib/head_music/content/rhythmic_value.rb
182
188
  - lib/head_music/content/staff.rb
183
189
  - lib/head_music/content/voice.rb
190
+ - lib/head_music/instruments/alternate_tuning.rb
191
+ - lib/head_music/instruments/alternate_tunings.yml
184
192
  - lib/head_music/instruments/instrument.rb
193
+ - lib/head_music/instruments/instrument_configuration.rb
194
+ - lib/head_music/instruments/instrument_configuration_option.rb
195
+ - lib/head_music/instruments/instrument_configurations.yml
185
196
  - lib/head_music/instruments/instrument_families.yml
186
197
  - lib/head_music/instruments/instrument_family.rb
187
198
  - lib/head_music/instruments/instruments.yml
199
+ - lib/head_music/instruments/playing_technique.rb
200
+ - lib/head_music/instruments/playing_techniques.yml
201
+ - lib/head_music/instruments/score_order.rb
202
+ - lib/head_music/instruments/score_orders.yml
188
203
  - lib/head_music/instruments/staff.rb
189
204
  - lib/head_music/instruments/staff_scheme.rb
205
+ - lib/head_music/instruments/stringing.rb
206
+ - lib/head_music/instruments/stringing_course.rb
207
+ - lib/head_music/instruments/stringings.yml
190
208
  - lib/head_music/instruments/variant.rb
191
209
  - lib/head_music/locales/de.yml
192
210
  - lib/head_music/locales/en.yml
@@ -196,35 +214,54 @@ files:
196
214
  - lib/head_music/locales/it.yml
197
215
  - lib/head_music/locales/ru.yml
198
216
  - lib/head_music/named.rb
217
+ - lib/head_music/notation.rb
218
+ - lib/head_music/notation/musical_symbol.rb
219
+ - lib/head_music/notation/staff_mapping.rb
220
+ - lib/head_music/notation/staff_position.rb
199
221
  - lib/head_music/rudiment/alteration.rb
222
+ - lib/head_music/rudiment/alterations.yml
223
+ - lib/head_music/rudiment/base.rb
200
224
  - lib/head_music/rudiment/chromatic_interval.rb
201
225
  - lib/head_music/rudiment/clef.rb
202
226
  - lib/head_music/rudiment/clefs.yml
203
227
  - lib/head_music/rudiment/consonance.rb
228
+ - lib/head_music/rudiment/diatonic_context.rb
229
+ - lib/head_music/rudiment/key.rb
204
230
  - lib/head_music/rudiment/key_signature.rb
205
231
  - lib/head_music/rudiment/key_signature/enharmonic_equivalence.rb
206
232
  - lib/head_music/rudiment/letter_name.rb
207
233
  - lib/head_music/rudiment/meter.rb
208
- - lib/head_music/rudiment/musical_symbol.rb
234
+ - lib/head_music/rudiment/mode.rb
235
+ - lib/head_music/rudiment/note.rb
209
236
  - lib/head_music/rudiment/pitch.rb
210
237
  - lib/head_music/rudiment/pitch/enharmonic_equivalence.rb
211
238
  - lib/head_music/rudiment/pitch/octave_equivalence.rb
239
+ - lib/head_music/rudiment/pitch/parser.rb
212
240
  - lib/head_music/rudiment/pitch_class.rb
213
241
  - lib/head_music/rudiment/quality.rb
214
242
  - lib/head_music/rudiment/reference_pitch.rb
215
243
  - lib/head_music/rudiment/register.rb
244
+ - lib/head_music/rudiment/rest.rb
216
245
  - lib/head_music/rudiment/rhythm.rb
246
+ - lib/head_music/rudiment/rhythmic_element.rb
217
247
  - lib/head_music/rudiment/rhythmic_unit.rb
248
+ - lib/head_music/rudiment/rhythmic_unit/parser.rb
249
+ - lib/head_music/rudiment/rhythmic_units.yml
250
+ - lib/head_music/rudiment/rhythmic_value.rb
251
+ - lib/head_music/rudiment/rhythmic_value/parser.rb
218
252
  - lib/head_music/rudiment/scale.rb
219
253
  - lib/head_music/rudiment/scale_degree.rb
220
254
  - lib/head_music/rudiment/scale_type.rb
221
255
  - lib/head_music/rudiment/solmization.rb
222
256
  - lib/head_music/rudiment/solmizations.yml
223
257
  - lib/head_music/rudiment/spelling.rb
258
+ - lib/head_music/rudiment/tempo.rb
259
+ - lib/head_music/rudiment/tonal_context.rb
224
260
  - lib/head_music/rudiment/tuning.rb
225
261
  - lib/head_music/rudiment/tuning/just_intonation.rb
226
262
  - lib/head_music/rudiment/tuning/meantone.rb
227
263
  - lib/head_music/rudiment/tuning/pythagorean.rb
264
+ - lib/head_music/rudiment/unpitched_note.rb
228
265
  - lib/head_music/style/analysis.rb
229
266
  - lib/head_music/style/annotation.rb
230
267
  - lib/head_music/style/guidelines/always_move.rb
@@ -265,17 +302,46 @@ files:
265
302
  - lib/head_music/style/guides/fux_cantus_firmus.rb
266
303
  - lib/head_music/style/guides/modern_cantus_firmus.rb
267
304
  - lib/head_music/style/mark.rb
305
+ - lib/head_music/style/medieval_tradition.rb
306
+ - lib/head_music/style/modern_tradition.rb
307
+ - lib/head_music/style/renaissance_tradition.rb
308
+ - lib/head_music/style/tradition.rb
309
+ - lib/head_music/time.rb
310
+ - lib/head_music/time/clock_position.rb
311
+ - lib/head_music/time/conductor.rb
312
+ - lib/head_music/time/meter_event.rb
313
+ - lib/head_music/time/meter_map.rb
314
+ - lib/head_music/time/musical_position.rb
315
+ - lib/head_music/time/smpte_timecode.rb
316
+ - lib/head_music/time/tempo_event.rb
317
+ - lib/head_music/time/tempo_map.rb
318
+ - lib/head_music/utilities/case.rb
268
319
  - lib/head_music/utilities/hash_key.rb
269
320
  - lib/head_music/version.rb
270
- - test_translations.rb
271
- - user_stories/backlog/band-score-order.md
272
- - user_stories/backlog/chamber-ensemble-score-order.md
273
- - user_stories/backlog/consonance-dissonance-classification.md
274
- - user_stories/backlog/dyad-analysis.md
275
- - user_stories/backlog/orchestral-score-order.md
276
- - user_stories/backlog/pitch-class-set-analysis.md
277
- - user_stories/backlog/pitch-set-classification.md
278
- - user_stories/backlog/sonority-identification.md
321
+ - user_stories/active/string-pitches.md
322
+ - user_stories/backlog/notation-style.md
323
+ - user_stories/backlog/organizing-content.md
324
+ - user_stories/done/consonance-dissonance-classification.md
325
+ - user_stories/done/dyad-analysis.md
326
+ - user_stories/done/epic--score-order/PLAN.md
327
+ - user_stories/done/epic--score-order/band-score-order.md
328
+ - user_stories/done/epic--score-order/chamber-ensemble-score-order.md
329
+ - user_stories/done/epic--score-order/orchestral-score-order.md
330
+ - user_stories/done/expand-playing-techniques.md
331
+ - user_stories/done/handle-time.md
332
+ - user_stories/done/handle-time.rb
333
+ - user_stories/done/instrument-architecture.md
334
+ - user_stories/done/instrument-variant.md
335
+ - user_stories/done/move-musical-symbol-to-notation.md
336
+ - user_stories/done/move-staff-mapping-to-notation.md
337
+ - user_stories/done/move-staff-position-to-notation.md
338
+ - user_stories/done/notation-module-foundation.md
339
+ - user_stories/done/percussion_set.md
340
+ - user_stories/done/pitch-class-set-analysis.md
341
+ - user_stories/done/sonority-identification.md
342
+ - user_stories/done/superclass-for-note.md
343
+ - user_stories/epics/notation-module.md
344
+ - user_stories/visioning/agentic-daw.md
279
345
  homepage: https://github.com/roberthead/head_music
280
346
  licenses:
281
347
  - MIT