head_music 8.3.0 → 9.0.1

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +53 -0
  3. data/CLAUDE.md +32 -15
  4. data/Gemfile.lock +1 -1
  5. data/MUSIC_THEORY.md +120 -0
  6. data/lib/head_music/analysis/diatonic_interval.rb +29 -27
  7. data/lib/head_music/analysis/interval_consonance.rb +51 -0
  8. data/lib/head_music/content/note.rb +1 -1
  9. data/lib/head_music/content/placement.rb +1 -1
  10. data/lib/head_music/content/position.rb +1 -1
  11. data/lib/head_music/content/staff.rb +1 -1
  12. data/lib/head_music/instruments/instrument.rb +103 -113
  13. data/lib/head_music/instruments/instrument_family.rb +13 -2
  14. data/lib/head_music/instruments/instrument_type.rb +188 -0
  15. data/lib/head_music/instruments/score_order.rb +139 -0
  16. data/lib/head_music/instruments/score_orders.yml +130 -0
  17. data/lib/head_music/instruments/variant.rb +6 -0
  18. data/lib/head_music/locales/de.yml +6 -0
  19. data/lib/head_music/locales/en.yml +6 -0
  20. data/lib/head_music/locales/es.yml +6 -0
  21. data/lib/head_music/locales/fr.yml +6 -0
  22. data/lib/head_music/locales/it.yml +6 -0
  23. data/lib/head_music/locales/ru.yml +6 -0
  24. data/lib/head_music/rudiment/alteration.rb +23 -8
  25. data/lib/head_music/rudiment/base.rb +9 -0
  26. data/lib/head_music/rudiment/chromatic_interval.rb +3 -6
  27. data/lib/head_music/rudiment/clef.rb +1 -1
  28. data/lib/head_music/rudiment/consonance.rb +37 -4
  29. data/lib/head_music/rudiment/diatonic_context.rb +25 -0
  30. data/lib/head_music/rudiment/key.rb +77 -0
  31. data/lib/head_music/rudiment/key_signature/enharmonic_equivalence.rb +1 -1
  32. data/lib/head_music/rudiment/key_signature.rb +46 -7
  33. data/lib/head_music/rudiment/letter_name.rb +3 -3
  34. data/lib/head_music/rudiment/meter.rb +19 -9
  35. data/lib/head_music/rudiment/mode.rb +92 -0
  36. data/lib/head_music/rudiment/musical_symbol.rb +1 -1
  37. data/lib/head_music/rudiment/note.rb +112 -0
  38. data/lib/head_music/rudiment/pitch/parser.rb +52 -0
  39. data/lib/head_music/rudiment/pitch.rb +5 -6
  40. data/lib/head_music/rudiment/pitch_class.rb +1 -1
  41. data/lib/head_music/rudiment/quality.rb +1 -1
  42. data/lib/head_music/rudiment/reference_pitch.rb +1 -1
  43. data/lib/head_music/rudiment/register.rb +4 -1
  44. data/lib/head_music/rudiment/rest.rb +36 -0
  45. data/lib/head_music/rudiment/rhythmic_element.rb +53 -0
  46. data/lib/head_music/rudiment/rhythmic_unit/parser.rb +86 -0
  47. data/lib/head_music/rudiment/rhythmic_unit.rb +13 -5
  48. data/lib/head_music/rudiment/rhythmic_units.yml +80 -0
  49. data/lib/head_music/rudiment/rhythmic_value/parser.rb +77 -0
  50. data/lib/head_music/{content → rudiment}/rhythmic_value.rb +23 -5
  51. data/lib/head_music/rudiment/scale.rb +4 -5
  52. data/lib/head_music/rudiment/scale_degree.rb +1 -1
  53. data/lib/head_music/rudiment/scale_type.rb +9 -3
  54. data/lib/head_music/rudiment/solmization.rb +1 -1
  55. data/lib/head_music/rudiment/spelling.rb +5 -4
  56. data/lib/head_music/rudiment/tempo.rb +85 -0
  57. data/lib/head_music/rudiment/tonal_context.rb +35 -0
  58. data/lib/head_music/rudiment/tuning.rb +1 -1
  59. data/lib/head_music/rudiment/unpitched_note.rb +62 -0
  60. data/lib/head_music/style/medieval_tradition.rb +26 -0
  61. data/lib/head_music/style/modern_tradition.rb +34 -0
  62. data/lib/head_music/style/renaissance_tradition.rb +26 -0
  63. data/lib/head_music/style/tradition.rb +21 -0
  64. data/lib/head_music/utilities/hash_key.rb +34 -2
  65. data/lib/head_music/version.rb +1 -1
  66. data/lib/head_music.rb +31 -10
  67. data/user_stories/active/handle-time.md +7 -0
  68. data/user_stories/active/handle-time.rb +177 -0
  69. data/user_stories/done/epic--score-order/PLAN.md +244 -0
  70. data/user_stories/done/instrument-variant.md +65 -0
  71. data/user_stories/done/superclass-for-note.md +30 -0
  72. data/user_stories/todo/agentic-daw.md +3 -0
  73. data/user_stories/{backlog → todo}/dyad-analysis.md +2 -10
  74. data/user_stories/todo/material-and-scores.md +10 -0
  75. data/user_stories/todo/organizing-content.md +72 -0
  76. data/user_stories/todo/percussion_set.md +1 -0
  77. data/user_stories/{backlog → todo}/pitch-class-set-analysis.md +40 -0
  78. data/user_stories/{backlog → todo}/pitch-set-classification.md +10 -0
  79. data/user_stories/{backlog → todo}/sonority-identification.md +20 -0
  80. metadata +43 -12
  81. data/TODO.md +0 -109
  82. /data/user_stories/{backlog → done/epic--score-order}/band-score-order.md +0 -0
  83. /data/user_stories/{backlog → done/epic--score-order}/chamber-ensemble-score-order.md +0 -0
  84. /data/user_stories/{backlog → done/epic--score-order}/orchestral-score-order.md +0 -0
  85. /data/user_stories/{backlog → todo}/consonance-dissonance-classification.md +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec01f26a90e391dbe250ca2587586ceb9bc062a8eba06d97f52767eaf08bb2f0
4
- data.tar.gz: b2253758a487b28f9e02ae6479da2586da39ff45337bca0a24f9634988ff9eb4
3
+ metadata.gz: 012ce64dd4174cbeec42f1d4825e9fd10af79ed8f4b83a3beedbc14a9aea34fa
4
+ data.tar.gz: a31dbb0b6b3d732bd41e1dbfe6a042a8395db05832d58848ec4d53e5ae4a4524
5
5
  SHA512:
6
- metadata.gz: 6633eb9a47b72f81a44225d475d60b67924136809d469ba2a45ffe39ea6c1356ffbecd79e64f931c15146dd00980a9ff220c2b5c95deb955e5b3cf0eec7fef67
7
- data.tar.gz: 5628ee5c9f0a442560f502d071f155e0d93771b3081572e9a98a86a154f387b0c9431662b051fd58bb9189b71906b5e7c9c29dbeddebd278f1d4a23d97416634
6
+ metadata.gz: a98367425dcfb4899b24ef2e7986a7fbc594202c960b553ab35d3cecd5ee0b5ecb10f65e1e458fe2d1797b70eded378fd319b2cbfc7b9a5a2e393773ce75f06b
7
+ data.tar.gz: d3baf95b28de6c2df0e3d14250ed9c335cb3793d598eb7cf1c417dd40b6463bb57ddcda19be309a1045e835809ad3b9ad45dc0fd21797563319069da35db76bc
data/CHANGELOG.md CHANGED
@@ -7,6 +7,59 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [9.0.0] - 2025-10-24
11
+
12
+ ### Added
13
+ - Added `HeadMusic::Rudiment::Pitch::Parser` for strict pitch parsing
14
+ - Added `HeadMusic::Rudiment::RhythmicValue::Parser` for rhythmic value parsing
15
+ - Both parsers provide standardized `.parse()` class method API
16
+
17
+ ### Changed
18
+ - `Pitch.from_name` now uses `Pitch::Parser` internally
19
+ - `RhythmicValue.get` now uses `RhythmicValue::Parser` internally
20
+ - `Note.get` now parses "pitch rhythmic_value" strings inline without Parse module
21
+
22
+ ### Removed
23
+ - **BREAKING**: Removed `HeadMusic::Parse::Pitch` class
24
+ - **BREAKING**: Removed `HeadMusic::Parse::RhythmicValue` class
25
+ - **BREAKING**: Removed `HeadMusic::Parse::RhythmicElement` class
26
+ - **BREAKING**: Removed entire `HeadMusic::Parse` module
27
+
28
+ ### Migration Guide
29
+
30
+ If you were using the removed Parse classes, migrate as follows:
31
+
32
+ ```ruby
33
+ # Before (v8.x)
34
+ parser = HeadMusic::Parse::Pitch.new("C#4")
35
+ pitch = parser.pitch
36
+
37
+ # After (v9.x)
38
+ pitch = HeadMusic::Rudiment::Pitch.get("C#4")
39
+ # or for strict parsing:
40
+ pitch = HeadMusic::Rudiment::Pitch::Parser.parse("C#4")
41
+ ```
42
+
43
+ ```ruby
44
+ # Before (v8.x)
45
+ parser = HeadMusic::Parse::RhythmicValue.new("dotted quarter")
46
+ value = parser.rhythmic_value
47
+
48
+ # After (v9.x)
49
+ value = HeadMusic::Rudiment::RhythmicValue.get("dotted quarter")
50
+ # or for strict parsing:
51
+ value = HeadMusic::Rudiment::RhythmicValue::Parser.parse("dotted quarter")
52
+ ```
53
+
54
+ ```ruby
55
+ # Before (v8.x)
56
+ parser = HeadMusic::Parse::RhythmicElement.new("F#4 dotted-quarter")
57
+ note = parser.note
58
+
59
+ # After (v9.x)
60
+ note = HeadMusic::Rudiment::Note.get("F#4 dotted-quarter")
61
+ ```
62
+
10
63
  ## [8.2.1] - 2025-06-21
11
64
 
12
65
  ### Added
data/CLAUDE.md CHANGED
@@ -41,14 +41,26 @@ bundle exec rake doc
41
41
  bundle exec rake doc_stats
42
42
  ```
43
43
 
44
- ### Linting and Formatting
44
+ ### Git Etiquette
45
45
 
46
- The project uses Standard Ruby for style enforcement. Always run linting before committing:
46
+ Do not make a commit unless I ask you to.
47
+
48
+ When composing git commit messages, follow best-practices. However, do not mention yourself (claude) or list yourself as a co-author.
49
+
50
+ This project uses a rebase flow and `main` as the mainline branch.
51
+
52
+ ### Code Style, Linting, and Formatting
53
+
54
+ The project uses Standard Ruby for style enforcement. Always run linting after editing and before committing.
47
55
 
48
56
  ```bash
49
- bundle exec rubocop
57
+ bundle exec rubocop -a
50
58
  ```
51
59
 
60
+ Always strip trailing whitespace from all lines being added or edited. Always include a blank line at the end of each file.
61
+
62
+ Do not use an assignment inside a condition.
63
+
52
64
  ### Testing
53
65
 
54
66
  Tests are written in RSpec and located in the `/spec` directory, mirroring the `/lib` structure. The project requires 90% code coverage minimum.
@@ -60,25 +72,25 @@ Tests are written in RSpec and located in the `/spec` directory, mirroring the `
60
72
  The codebase follows a domain-driven design with clear module boundaries:
61
73
 
62
74
  1. **HeadMusic::Rudiment** - Core music theory elements
63
- - Pitch, Note, Scale, Key, Interval, Chord
64
- - Factory methods: `.get()` for most rudiments
75
+ - Pitch, Note, Scale, Key, Interval, Chord
76
+ - Factory methods: `.get()` for most rudiments
65
77
 
66
78
  2. **HeadMusic::Analysis** - Musical analysis tools
67
- - Intervals, Chords, Motion analysis
68
- - Harmonic and melodic analysis
79
+ - Intervals, Chords, Motion analysis
80
+ - Harmonic and melodic analysis
69
81
 
70
82
  3. **HeadMusic::Content** - Musical composition representation
71
- - Composition, Voice, Note, Rest
72
- - Rhythmic values and time signatures
83
+ - Composition, Voice, Note, Rest
84
+ - Rhythmic values and time signatures
73
85
 
74
86
  4. **HeadMusic::Instruments** - Instrument definitions
75
- - Instrument families and properties
76
- - Pitch ranges and transposition
87
+ - Instrument families and properties
88
+ - Pitch ranges and transposition
77
89
 
78
90
  5. **HeadMusic::Style** - Composition rules and guidelines
79
- - Counterpoint rules
80
- - Voice leading guidelines
81
- - Style analysis
91
+ - Counterpoint rules
92
+ - Voice leading guidelines
93
+ - Style analysis
82
94
 
83
95
  ### Key Design Patterns
84
96
 
@@ -115,6 +127,7 @@ The gem supports multiple languages through the HeadMusic::Named mixin:
115
127
  - Follow Standard Ruby style guide
116
128
  - Use YARD documentation format for public methods
117
129
  - Prefer delegation over inheritance
130
+ - Always run `bundle exec rubocop -a` after editing ruby code
118
131
 
119
132
  ## Common Development Tasks
120
133
 
@@ -131,4 +144,8 @@ The gem supports multiple languages through the HeadMusic::Named mixin:
131
144
  1. Check for dependent classes that might be affected
132
145
  2. Run tests for the specific module: `bundle exec rspec spec/head_music/[module_name]`
133
146
  3. Update documentation with YARD comments
134
- 4. Ensure translations are updated if names change
147
+ 4. Ensure translations are updated if names change
148
+
149
+ ## Music theory and concepts
150
+
151
+ Please refer to MUSIC_THEORY.md for music theory domain knowledge.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- head_music (8.3.0)
4
+ head_music (9.0.0)
5
5
  activesupport (~> 7.0)
6
6
  humanize (~> 2.0)
7
7
  i18n (~> 1.8)
data/MUSIC_THEORY.md ADDED
@@ -0,0 +1,120 @@
1
+ # Music Theory
2
+ Domain-specific knowledge for this project.
3
+
4
+ ## Rudiments
5
+
6
+ The rudiments of music theory are built up piece-by-piece.
7
+
8
+ letter name
9
+ - C, D, E, F, G, A, B, …
10
+ - equivalent to:
11
+ - do, re, mi, fa, sol, la, si/ti, …
12
+
13
+ alteration
14
+ - sharp, flat, double sharp, double flat
15
+ - optional
16
+ - none is same as 'natural'
17
+ - found in key signatures
18
+ - found in bars as accidentals
19
+
20
+ spelling
21
+ - letter name + alteration
22
+ - example: "E♭"
23
+
24
+ register
25
+ - an integer typically between 0 and 8
26
+ - represents the octaves of an 88-key piano
27
+ - scientific pitch notation
28
+ - middle C is C4
29
+ - increments between B and C
30
+ - a half step below C4 is B3.
31
+
32
+ pitch
33
+ - spelling + register
34
+ - example: "E♭3"
35
+
36
+ rhythmic unit
37
+ - duration
38
+ - expressed in fractions (or multiples) of a standard whole note
39
+ - whole, half, quarter, eighth, sixteenth, …
40
+ - breve, …
41
+
42
+ rhythmic value (duration)
43
+ - a rhythmic unit plus optional augmentation dots
44
+ - augmentation dots extend the duration of the rhythmic unit
45
+ - one dot extends the rhythmic value 50%
46
+ - two dots extend the rhythmic value 75%
47
+ - two dots extend the rhythmic value 87.5%
48
+
49
+ rest
50
+ - a rhythmic value that passes in silence
51
+
52
+ note
53
+ - pitch + rhythmic value
54
+ - example: "E♭3 dotted quarter"
55
+
56
+ unpitched note
57
+ - an unpitched percussion note, such as a drum hit
58
+ - a sounded rhythmic value without a specific pitch
59
+
60
+ tied duration
61
+ - combines multiple rhythmic values into one longer note
62
+ - ties allow rhythmic values to be combined across barlines or strong beats
63
+
64
+ articulation
65
+ - a category of expressions that modify how one or more notes are performed.
66
+ - level of connection
67
+ - staccatissimo - the most staccato, even shorted and more clipped
68
+ - staccato – detatched (shortened to lease space between adjacent notes)
69
+ - tenuto - held of the full value
70
+ - legato - smoothly connected
71
+ - emphasis
72
+ - accent - play with emphasis or a stronger attack
73
+ - marcato - markedly emphasized
74
+ - instrument specific
75
+ - bowings
76
+ - breath mark
77
+ - roll mark
78
+
79
+ ## Instrument Families
80
+
81
+ There are several ways that people talk about families and other categorizations of instruments. For example, the "string family" or "woodwind family", but also more specifically, the word family is applied more specifically (e.g. the "oboe family").
82
+
83
+ ### Text Conversation with Brian Head (May 7, 2023)
84
+
85
+ Brian Head, brother and faculty at USC Thornton School of Music
86
+ https://music.usc.edu/brian-head/
87
+
88
+ Robert Head:
89
+ Hey, Brian. You have a sec for a music question? I’m trying to come up with different terms for the way “family” is used. “Woodwind family” vs. “Oboe family”.
90
+
91
+ Brian Head:
92
+ Those are good, I’d say. In what context?
93
+
94
+ Robert Head:
95
+ In my software project, I’m trying to define those relationships. One is a section of the orchestra and the other is species of instrument. But usually people, in my experience, just say “family”.
96
+ Is there some more precise terminology or adjective that can disambiguate those two terms?
97
+
98
+ Brian Head:
99
+ Hmmm. Already “family” is informal. Blatter distinguishes between “choir” and “family” as in the trumpet family” within the “brass choir”.
100
+
101
+ Robert Head:
102
+ Ah, yes! I do like that.
103
+ But does it apply to percussion?
104
+ “Section” is another candidate, but that gets used for string parts as well.
105
+
106
+ Brian Head:
107
+ Strings and percussion probably don’t think of themselves as a choir, but if you’re mainly looking for a taxonomically consistent word, that’s the feat I can think of at the moment.
108
+ Section is a good word, too, which easily flows between smaller and larger meanings.
109
+
110
+ Robert Head:
111
+ Obviously, the four “families” is a garbage way to classify all instruments and it really is more applicable to the orchestral context, so maybe “orchestra family” or “orchestra section”.
112
+
113
+ Brian Head:
114
+ I’d say that “family” is best used at the instrument level, as in “saxophone family”. Choir or section are better for larger collections. Still, both of those words connote membership in an orchestra. Or large ensemble. “Woodwinds” or “percussion” describe the class of instruments themselves.
115
+
116
+ Robert Head:
117
+ Cool
118
+
119
+ Action Item: Call them orchestra_section
120
+ DONE
@@ -57,16 +57,17 @@ class HeadMusic::Analysis::DiatonicInterval
57
57
 
58
58
  alias_method :to_i, :semitones
59
59
 
60
- # Override Named module methods to use computed name from naming
60
+ # Override Named module method to try I18n and fall back to computed name
61
61
  def name(locale_code: nil)
62
62
  if locale_code
63
- # Try to get translation from locale files
64
- name_key = naming.name.downcase.gsub(" ", "_").to_sym
65
- translation = I18n.translate(name_key, scope: "head_music.diatonic_intervals", locale: locale_code, default: nil)
66
- translation || naming.name
67
- else
68
- naming.name
63
+ name_key = HeadMusic::Utilities::HashKey.for(naming.name)
64
+ if I18n.backend.translations[locale_code]
65
+ locale_data = I18n.backend.translations[locale_code][:head_music] || {}
66
+ return locale_data[:diatonic_intervals][name_key] if locale_data.dig(:diatonic_intervals, name_key)
67
+ return locale_data[:chromatic_intervals][name_key] if locale_data.dig(:chromatic_intervals, name_key)
68
+ end
69
69
  end
70
+ naming.name
70
71
  end
71
72
 
72
73
  def to_s
@@ -111,26 +112,39 @@ class HeadMusic::Analysis::DiatonicInterval
111
112
  alias_method :invert, :inversion
112
113
 
113
114
  def consonance(style = :standard_practice)
114
- consonance_for_perfect(style) ||
115
- consonance_for_major_and_minor ||
116
- HeadMusic::Rudiment::Consonance.get(:dissonant)
115
+ consonance_analysis(style).consonance
117
116
  end
118
117
 
119
118
  def consonance?(style = :standard_practice)
120
- consonance(style).perfect? || consonance(style).imperfect?
119
+ consonance(style).consonant?
120
+ end
121
+
122
+ def consonant?(style = :standard_practice)
123
+ consonance_analysis(style).consonant?
121
124
  end
122
- alias_method :consonant?, :consonance?
123
125
 
124
126
  def perfect_consonance?(style = :standard_practice)
125
- consonance(style).perfect?
127
+ consonance_analysis(style).perfect_consonance?
126
128
  end
127
129
 
128
130
  def imperfect_consonance?(style = :standard_practice)
129
- consonance(style).imperfect?
131
+ consonance_analysis(style).imperfect_consonance?
130
132
  end
131
133
 
132
134
  def dissonance?(style = :standard_practice)
133
- consonance(style).dissonant?
135
+ consonance_analysis(style).dissonant?
136
+ end
137
+
138
+ def dissonant?(style = :standard_practice)
139
+ consonance_analysis(style).dissonant?
140
+ end
141
+
142
+ def consonance_analysis(style = :standard_practice)
143
+ HeadMusic::Analysis::IntervalConsonance.new(self, style)
144
+ end
145
+
146
+ def consonance_classification(style: :standard_practice)
147
+ consonance_analysis(style).classification
134
148
  end
135
149
 
136
150
  def above(pitch)
@@ -181,16 +195,4 @@ class HeadMusic::Analysis::DiatonicInterval
181
195
  def naming
182
196
  @naming ||= Naming.new(number: number, semitones: semitones)
183
197
  end
184
-
185
- def consonance_for_perfect(style = :standard_practice)
186
- HeadMusic::Rudiment::Consonance.get(dissonant_fourth?(style) ? :dissonant : :perfect) if perfect?
187
- end
188
-
189
- def consonance_for_major_and_minor
190
- HeadMusic::Rudiment::Consonance.get((third_or_compound? || sixth_or_compound?) ? :imperfect : :dissonant) if major? || minor?
191
- end
192
-
193
- def dissonant_fourth?(style = :standard_practice)
194
- fourth_or_compound? && style == :two_part_harmony
195
- end
196
198
  end
@@ -0,0 +1,51 @@
1
+ # Analysis class that combines an interval with a style tradition to determine consonance
2
+ class HeadMusic::Analysis::IntervalConsonance
3
+ attr_reader :interval, :style_tradition
4
+
5
+ def initialize(interval, style_tradition = HeadMusic::Style::ModernTradition.new)
6
+ @interval = interval
7
+ @style_tradition = style_tradition.is_a?(HeadMusic::Style::Tradition) ?
8
+ style_tradition :
9
+ HeadMusic::Style::Tradition.get(style_tradition)
10
+ end
11
+
12
+ def classification
13
+ @classification ||= style_tradition.consonance_classification(interval)
14
+ end
15
+
16
+ def consonance
17
+ @consonance ||= HeadMusic::Rudiment::Consonance.get(classification)
18
+ end
19
+
20
+ def consonant?
21
+ [HeadMusic::Rudiment::Consonance::PERFECT_CONSONANCE, HeadMusic::Rudiment::Consonance::IMPERFECT_CONSONANCE].include?(classification)
22
+ end
23
+
24
+ def dissonant?
25
+ [HeadMusic::Rudiment::Consonance::MILD_DISSONANCE, HeadMusic::Rudiment::Consonance::HARSH_DISSONANCE, HeadMusic::Rudiment::Consonance::DISSONANCE].include?(classification)
26
+ end
27
+
28
+ def contextual?
29
+ classification == HeadMusic::Rudiment::Consonance::CONTEXTUAL
30
+ end
31
+
32
+ def perfect_consonance?
33
+ classification == HeadMusic::Rudiment::Consonance::PERFECT_CONSONANCE
34
+ end
35
+
36
+ def imperfect_consonance?
37
+ classification == HeadMusic::Rudiment::Consonance::IMPERFECT_CONSONANCE
38
+ end
39
+
40
+ def mild_dissonance?
41
+ classification == HeadMusic::Rudiment::Consonance::MILD_DISSONANCE
42
+ end
43
+
44
+ def harsh_dissonance?
45
+ classification == HeadMusic::Rudiment::Consonance::HARSH_DISSONANCE
46
+ end
47
+
48
+ def dissonance?
49
+ classification == HeadMusic::Rudiment::Consonance::DISSONANCE
50
+ end
51
+ end
@@ -11,7 +11,7 @@ class HeadMusic::Content::Note
11
11
 
12
12
  def initialize(pitch, rhythmic_value, voice = nil, position = nil)
13
13
  @pitch = HeadMusic::Rudiment::Pitch.get(pitch)
14
- @rhythmic_value = HeadMusic::Content::RhythmicValue.get(rhythmic_value)
14
+ @rhythmic_value = HeadMusic::Rudiment::RhythmicValue.get(rhythmic_value)
15
15
  @voice = voice || HeadMusic::Content::Voice.new
16
16
  @position = position || HeadMusic::Content::Position.new(@voice.composition, "1:1")
17
17
  end
@@ -55,7 +55,7 @@ class HeadMusic::Content::Placement
55
55
  def ensure_attributes(voice, position, rhythmic_value, pitch)
56
56
  @voice = voice
57
57
  ensure_position(position)
58
- @rhythmic_value = HeadMusic::Content::RhythmicValue.get(rhythmic_value)
58
+ @rhythmic_value = HeadMusic::Rudiment::RhythmicValue.get(rhythmic_value)
59
59
  @pitch = HeadMusic::Rudiment::Pitch.get(pitch)
60
60
  end
61
61
 
@@ -53,7 +53,7 @@ class HeadMusic::Content::Position
53
53
  end
54
54
 
55
55
  def +(other)
56
- other = HeadMusic::Content::RhythmicValue.new(other) if [HeadMusic::Rudiment::RhythmicUnit, Symbol, String].include?(other.class)
56
+ other = HeadMusic::Rudiment::RhythmicValue.new(other) if [HeadMusic::Rudiment::RhythmicUnit, Symbol, String].include?(other.class)
57
57
  self.class.new(composition, bar_number, count, tick + other.ticks)
58
58
  end
59
59
 
@@ -8,7 +8,7 @@ class HeadMusic::Content::Staff
8
8
  attr_reader :default_clef, :line_count, :instrument
9
9
 
10
10
  def initialize(default_clef_key, instrument: nil, line_count: nil)
11
- @instrument = HeadMusic::Instruments::Instrument.get(instrument) if instrument
11
+ @instrument = HeadMusic::Instruments::InstrumentType.get(instrument) if instrument
12
12
  begin
13
13
  @default_clef = HeadMusic::Rudiment::Clef.get(default_clef_key)
14
14
  rescue KeyError, NoMethodError