head_music 8.2.0 → 8.3.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/.github/workflows/release.yml +1 -1
- data/CHANGELOG.md +14 -0
- data/CLAUDE.md +134 -0
- data/Gemfile.lock +25 -25
- data/Rakefile +2 -2
- data/TODO.md +41 -150
- data/bin/check_instrument_consistency.rb +86 -0
- data/check_instrument_consistency.rb +0 -0
- data/head_music.gemspec +1 -1
- data/lib/head_music/analysis/diatonic_interval/naming.rb +1 -1
- data/lib/head_music/analysis/diatonic_interval.rb +28 -7
- data/lib/head_music/analysis/sonority.rb +1 -1
- data/lib/head_music/content/staff.rb +13 -3
- data/lib/head_music/content/voice.rb +8 -0
- data/lib/head_music/instruments/instrument.rb +1 -3
- data/lib/head_music/instruments/instrument_families.yml +37 -2
- data/lib/head_music/instruments/instruments.yml +352 -367
- data/lib/head_music/instruments/variant.rb +1 -1
- data/lib/head_music/locales/de.yml +20 -0
- data/lib/head_music/locales/en.yml +92 -0
- data/lib/head_music/locales/es.yml +19 -0
- data/lib/head_music/locales/fr.yml +19 -0
- data/lib/head_music/locales/it.yml +20 -0
- data/lib/head_music/locales/ru.yml +21 -2
- data/lib/head_music/rudiment/rhythmic_unit.rb +93 -26
- data/lib/head_music/rudiment/scale_degree.rb +8 -3
- data/lib/head_music/rudiment/tuning/just_intonation.rb +85 -0
- data/lib/head_music/rudiment/tuning/meantone.rb +87 -0
- data/lib/head_music/rudiment/tuning/pythagorean.rb +91 -0
- data/lib/head_music/rudiment/tuning.rb +17 -3
- data/lib/head_music/style/annotation.rb +6 -6
- data/lib/head_music/style/guidelines/consonant_climax.rb +2 -2
- data/lib/head_music/style/guidelines/notes_same_length.rb +16 -16
- data/lib/head_music/version.rb +1 -1
- data/lib/head_music.rb +3 -0
- data/user_stories/backlog/band-score-order.md +38 -0
- data/user_stories/backlog/chamber-ensemble-score-order.md +33 -0
- data/user_stories/backlog/consonance-dissonance-classification.md +57 -0
- data/user_stories/backlog/dyad-analysis.md +65 -0
- data/user_stories/backlog/orchestral-score-order.md +43 -0
- data/user_stories/backlog/pitch-class-set-analysis.md +39 -0
- data/user_stories/backlog/pitch-set-classification.md +62 -0
- data/user_stories/backlog/sonority-identification.md +47 -0
- metadata +18 -4
@@ -4,8 +4,8 @@ module HeadMusic::Analysis; end
|
|
4
4
|
# A diatonic interval is the distance between two spelled pitches.
|
5
5
|
class HeadMusic::Analysis::DiatonicInterval
|
6
6
|
include Comparable
|
7
|
+
include HeadMusic::Named
|
7
8
|
|
8
|
-
# TODO: include Named module
|
9
9
|
NUMBER_NAMES = %w[
|
10
10
|
unison second third fourth fifth sixth seventh octave
|
11
11
|
ninth tenth eleventh twelfth thirteenth fourteenth fifteenth
|
@@ -43,7 +43,6 @@ class HeadMusic::Analysis::DiatonicInterval
|
|
43
43
|
|
44
44
|
attr_reader :lower_pitch, :higher_pitch
|
45
45
|
|
46
|
-
delegate :to_s, to: :name
|
47
46
|
delegate :perfect?, :major?, :minor?, :diminished?, :augmented?, :doubly_diminished?, :doubly_augmented?, to: :quality
|
48
47
|
|
49
48
|
delegate :step?, :skip?, :leap?, :large_leap?, to: :category
|
@@ -52,18 +51,40 @@ class HeadMusic::Analysis::DiatonicInterval
|
|
52
51
|
to: :size
|
53
52
|
)
|
54
53
|
delegate(
|
55
|
-
:simple_name, :quality_name, :simple_number_name, :number_name, :
|
54
|
+
:simple_name, :quality_name, :simple_number_name, :number_name, :shorthand,
|
56
55
|
to: :naming
|
57
56
|
)
|
58
57
|
|
59
58
|
alias_method :to_i, :semitones
|
60
59
|
|
60
|
+
# Override Named module methods to use computed name from naming
|
61
|
+
def name(locale_code: nil)
|
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
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
name
|
74
|
+
end
|
75
|
+
|
61
76
|
# Accepts a name and returns the interval with middle c on the bottom
|
62
77
|
def self.get(identifier)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
78
|
+
if identifier.is_a?(String) || identifier.is_a?(Symbol)
|
79
|
+
name = Parser.new(identifier)
|
80
|
+
semitones = Semitones.new(name.degree_name.to_sym, name.quality_name).count
|
81
|
+
higher_pitch = HeadMusic::Rudiment::Pitch.from_number_and_letter(HeadMusic::Rudiment::Pitch.middle_c + semitones, name.higher_letter)
|
82
|
+
interval = new(HeadMusic::Rudiment::Pitch.middle_c, higher_pitch)
|
83
|
+
interval.ensure_localized_name(name: identifier.to_s)
|
84
|
+
interval
|
85
|
+
else
|
86
|
+
identifier
|
87
|
+
end
|
67
88
|
end
|
68
89
|
|
69
90
|
def initialize(first_pitch, second_pitch)
|
@@ -110,7 +110,7 @@ class HeadMusic::Analysis::Sonority
|
|
110
110
|
alias_method :quintal?, :quartal?
|
111
111
|
|
112
112
|
def diatonic_intervals_above_bass_pitch
|
113
|
-
return
|
113
|
+
return [] unless identifier
|
114
114
|
|
115
115
|
@diatonic_intervals_above_bass_pitch ||=
|
116
116
|
SONORITIES[identifier].map { |shorthand| HeadMusic::Analysis::DiatonicInterval.get(shorthand) }
|
@@ -8,12 +8,22 @@ 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
|
-
@default_clef = HeadMusic::Rudiment::Clef.get(default_clef_key)
|
12
|
-
@line_count = line_count || DEFAULT_LINE_COUNT
|
13
11
|
@instrument = HeadMusic::Instruments::Instrument.get(instrument) if instrument
|
12
|
+
begin
|
13
|
+
@default_clef = HeadMusic::Rudiment::Clef.get(default_clef_key)
|
14
|
+
rescue KeyError, NoMethodError
|
15
|
+
puts("Warning: Clef '#{default_clef_key}' not found.")
|
16
|
+
if @instrument
|
17
|
+
puts("Using instrument clef.")
|
18
|
+
@default_clef = @instrument.default_staves.first.clef
|
19
|
+
else
|
20
|
+
@default_clef = HeadMusic::Rudiment::Clef.get(:treble_clef)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
@line_count = line_count || DEFAULT_LINE_COUNT
|
14
24
|
end
|
15
25
|
|
16
26
|
def clef
|
17
|
-
default_clef
|
27
|
+
default_clef
|
18
28
|
end
|
19
29
|
end
|
@@ -110,6 +110,14 @@ class HeadMusic::Content::Voice
|
|
110
110
|
placements.last.position.bar_number
|
111
111
|
end
|
112
112
|
|
113
|
+
def last_placement
|
114
|
+
placements.last
|
115
|
+
end
|
116
|
+
|
117
|
+
def next_position
|
118
|
+
last_placement ? last_placement.next_position : HeadMusic::Content::Position.new(composition, 1, 1, 0)
|
119
|
+
end
|
120
|
+
|
113
121
|
def to_s
|
114
122
|
return pitches_string if role.to_s.strip == ""
|
115
123
|
|
@@ -82,9 +82,7 @@ class HeadMusic::Instruments::Instrument
|
|
82
82
|
variants.find(&:default?) || variants.first
|
83
83
|
end
|
84
84
|
|
85
|
-
|
86
|
-
default_variant&.default_staff_scheme
|
87
|
-
end
|
85
|
+
delegate :default_staff_scheme, to: :default_variant
|
88
86
|
|
89
87
|
def default_staves
|
90
88
|
default_staff_scheme&.staves || []
|
@@ -14,6 +14,12 @@ bagpipe:
|
|
14
14
|
- wind
|
15
15
|
- woodwind
|
16
16
|
orchestra_section_key: woodwind
|
17
|
+
bass_drum:
|
18
|
+
classification_keys:
|
19
|
+
- percussion
|
20
|
+
- membranophone
|
21
|
+
- unpitched
|
22
|
+
orchestra_section_key: percussion
|
17
23
|
bassoon:
|
18
24
|
classification_keys:
|
19
25
|
- aerophone
|
@@ -22,6 +28,15 @@ bassoon:
|
|
22
28
|
- wind
|
23
29
|
- woodwind
|
24
30
|
orchestra_section_key: woodwind
|
31
|
+
celesta:
|
32
|
+
classification_keys:
|
33
|
+
- idiophone
|
34
|
+
- keyboard
|
35
|
+
- percussion
|
36
|
+
- struck
|
37
|
+
- metal
|
38
|
+
- pitched
|
39
|
+
orchestra_section_key: keyboard
|
25
40
|
clarinet:
|
26
41
|
classification_keys:
|
27
42
|
- aerophone
|
@@ -34,13 +49,13 @@ clavichord:
|
|
34
49
|
classification_keys:
|
35
50
|
- chordophone
|
36
51
|
- keyboard
|
37
|
-
- percussion
|
38
52
|
- string
|
39
53
|
orchestra_section_key: keyboard
|
40
54
|
cornet:
|
41
55
|
classification_keys:
|
42
56
|
- aerophone
|
43
57
|
- brass
|
58
|
+
- valve
|
44
59
|
- wind
|
45
60
|
orchestra_section_key: brass
|
46
61
|
cymbal:
|
@@ -57,6 +72,7 @@ double_bass:
|
|
57
72
|
classification_keys:
|
58
73
|
- bowed
|
59
74
|
- chordophone
|
75
|
+
- unfretted
|
60
76
|
- string
|
61
77
|
orchestra_section_key: string
|
62
78
|
flute:
|
@@ -86,6 +102,7 @@ guitar:
|
|
86
102
|
classification_keys:
|
87
103
|
- chordophone
|
88
104
|
- plucked
|
105
|
+
- fretted
|
89
106
|
- string
|
90
107
|
orchestra_section_key: string
|
91
108
|
harmonica:
|
@@ -105,13 +122,13 @@ harpsichord:
|
|
105
122
|
classification_keys:
|
106
123
|
- chordophone
|
107
124
|
- keyboard
|
108
|
-
- percussion
|
109
125
|
- string
|
110
126
|
orchestra_section_key: keyboard
|
111
127
|
horn:
|
112
128
|
classification_keys:
|
113
129
|
- aerophone
|
114
130
|
- brass
|
131
|
+
- valve
|
115
132
|
- wind
|
116
133
|
orchestra_section_key: brass
|
117
134
|
kettledrum:
|
@@ -124,12 +141,14 @@ lute:
|
|
124
141
|
classification_keys:
|
125
142
|
- chordophone
|
126
143
|
- plucked
|
144
|
+
- fretted
|
127
145
|
- string
|
128
146
|
orchestra_section_key: string
|
129
147
|
mandolin:
|
130
148
|
classification_keys:
|
131
149
|
- chordophone
|
132
150
|
- plucked
|
151
|
+
- fretted
|
133
152
|
- string
|
134
153
|
orchestra_section_key: string
|
135
154
|
marimba:
|
@@ -141,6 +160,7 @@ marimba:
|
|
141
160
|
- wood
|
142
161
|
- mallet
|
143
162
|
- pitched
|
163
|
+
- resonator
|
144
164
|
orchestra_section_key: percussion
|
145
165
|
oboe:
|
146
166
|
classification_keys:
|
@@ -172,6 +192,7 @@ saxhorn:
|
|
172
192
|
classification_keys:
|
173
193
|
- aerophone
|
174
194
|
- brass
|
195
|
+
- valve
|
175
196
|
- wind
|
176
197
|
orchestra_section_key: brass
|
177
198
|
saxophone:
|
@@ -186,6 +207,7 @@ sitar:
|
|
186
207
|
classification_keys:
|
187
208
|
- chordophone
|
188
209
|
- plucked
|
210
|
+
- fretted
|
189
211
|
- string
|
190
212
|
orchestra_section_key: string
|
191
213
|
snare_drum:
|
@@ -213,6 +235,14 @@ tabla:
|
|
213
235
|
- membranophone
|
214
236
|
- pitched
|
215
237
|
orchestra_section_key: percussion
|
238
|
+
tambourine:
|
239
|
+
classification_keys:
|
240
|
+
- percussion
|
241
|
+
- membranophone
|
242
|
+
- shaken
|
243
|
+
- idiophone
|
244
|
+
- unpitched
|
245
|
+
orchestra_section_key: percussion
|
216
246
|
theremin:
|
217
247
|
classification_keys:
|
218
248
|
- electronic
|
@@ -226,18 +256,21 @@ trumpet:
|
|
226
256
|
classification_keys:
|
227
257
|
- aerophone
|
228
258
|
- brass
|
259
|
+
- valve
|
229
260
|
- wind
|
230
261
|
orchestra_section_key: brass
|
231
262
|
tuba:
|
232
263
|
classification_keys:
|
233
264
|
- aerophone
|
234
265
|
- brass
|
266
|
+
- valve
|
235
267
|
- wind
|
236
268
|
orchestra_section_key: brass
|
237
269
|
ukulele:
|
238
270
|
classification_keys:
|
239
271
|
- chordophone
|
240
272
|
- plucked
|
273
|
+
- fretted
|
241
274
|
- string
|
242
275
|
orchestra_section_key: string
|
243
276
|
vibraphone:
|
@@ -249,11 +282,13 @@ vibraphone:
|
|
249
282
|
- mallet
|
250
283
|
- metal
|
251
284
|
- pitched
|
285
|
+
- resonator
|
252
286
|
orchestra_section_key: percussion
|
253
287
|
violin:
|
254
288
|
classification_keys:
|
255
289
|
- bowed
|
256
290
|
- chordophone
|
291
|
+
- unfretted
|
257
292
|
- string
|
258
293
|
orchestra_section_key: string
|
259
294
|
voice:
|