head_music 7.0.5 → 8.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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/Gemfile +1 -1
- data/lib/head_music/{circle.rb → analysis/circle.rb} +9 -6
- data/lib/head_music/{diatonic_interval → analysis/diatonic_interval}/category.rb +1 -1
- data/lib/head_music/{diatonic_interval → analysis/diatonic_interval}/naming.rb +6 -6
- data/lib/head_music/{diatonic_interval → analysis/diatonic_interval}/parser.rb +4 -4
- data/lib/head_music/{diatonic_interval → analysis/diatonic_interval}/semitones.rb +4 -4
- data/lib/head_music/{diatonic_interval → analysis/diatonic_interval}/size.rb +1 -1
- data/lib/head_music/{diatonic_interval.rb → analysis/diatonic_interval.rb} +19 -16
- data/lib/head_music/{harmonic_interval.rb → analysis/harmonic_interval.rb} +5 -2
- data/lib/head_music/{interval_cycle.rb → analysis/interval_cycle.rb} +12 -9
- data/lib/head_music/{melodic_interval.rb → analysis/melodic_interval.rb} +7 -4
- data/lib/head_music/{motion.rb → analysis/motion.rb} +6 -3
- data/lib/head_music/{pitch_class_set.rb → analysis/pitch_class_set.rb} +5 -2
- data/lib/head_music/{pitch_set.rb → analysis/pitch_set.rb} +14 -11
- data/lib/head_music/{sonority.rb → analysis/sonority.rb} +7 -4
- data/lib/head_music/content/bar.rb +2 -2
- data/lib/head_music/content/composition.rb +3 -3
- data/lib/head_music/content/note.rb +1 -1
- data/lib/head_music/content/placement.rb +1 -1
- data/lib/head_music/content/position.rb +1 -1
- data/lib/head_music/content/rhythmic_value.rb +3 -3
- data/lib/head_music/{staff.rb → content/staff.rb} +6 -3
- data/lib/head_music/content/voice.rb +2 -2
- data/lib/head_music/{instrument.rb → instruments/instrument.rb} +10 -7
- data/lib/head_music/{data → instruments}/instrument_families.yml +49 -0
- data/lib/head_music/{instrument_family.rb → instruments/instrument_family.rb} +5 -2
- data/lib/head_music/{data → instruments}/instruments.yml +116 -0
- data/lib/head_music/{instrument → instruments}/staff.rb +5 -2
- data/lib/head_music/{instrument → instruments}/staff_scheme.rb +7 -2
- data/lib/head_music/{instrument → instruments}/variant.rb +6 -3
- data/lib/head_music/locales/en.yml +22 -0
- data/lib/head_music/{alteration.rb → rudiment/alteration.rb} +9 -6
- data/lib/head_music/{chromatic_interval.rb → rudiment/chromatic_interval.rb} +7 -4
- data/lib/head_music/{clef.rb → rudiment/clef.rb} +7 -4
- data/lib/head_music/{consonance.rb → rudiment/consonance.rb} +4 -1
- data/lib/head_music/{key_signature → rudiment/key_signature}/enharmonic_equivalence.rb +4 -4
- data/lib/head_music/{key_signature.rb → rudiment/key_signature.rb} +10 -7
- data/lib/head_music/{letter_name.rb → rudiment/letter_name.rb} +9 -6
- data/lib/head_music/{meter.rb → rudiment/meter.rb} +6 -3
- data/lib/head_music/{musical_symbol.rb → rudiment/musical_symbol.rb} +4 -1
- data/lib/head_music/{pitch → rudiment/pitch}/enharmonic_equivalence.rb +4 -4
- data/lib/head_music/{pitch → rudiment/pitch}/octave_equivalence.rb +2 -2
- data/lib/head_music/{pitch.rb → rudiment/pitch.rb} +30 -27
- data/lib/head_music/{pitch_class.rb → rudiment/pitch_class.rb} +14 -11
- data/lib/head_music/{quality.rb → rudiment/quality.rb} +4 -1
- data/lib/head_music/{reference_pitch.rb → rudiment/reference_pitch.rb} +5 -2
- data/lib/head_music/{register.rb → rudiment/register.rb} +6 -3
- data/lib/head_music/rudiment/rhythm.rb +6 -0
- data/lib/head_music/{rhythmic_unit.rb → rudiment/rhythmic_unit.rb} +5 -2
- data/lib/head_music/{scale.rb → rudiment/scale.rb} +12 -9
- data/lib/head_music/{scale_degree.rb → rudiment/scale_degree.rb} +8 -5
- data/lib/head_music/{scale_type.rb → rudiment/scale_type.rb} +4 -1
- data/lib/head_music/{solmization.rb → rudiment/solmization.rb} +4 -1
- data/lib/head_music/{spelling.rb → rudiment/spelling.rb} +20 -17
- data/lib/head_music/{tuning.rb → rudiment/tuning.rb} +6 -3
- data/lib/head_music/style/annotation.rb +6 -6
- data/lib/head_music/style/guidelines/consonant_climax.rb +4 -4
- data/lib/head_music/style/guidelines/diatonic.rb +1 -1
- data/lib/head_music/style/guidelines/step_out_of_unison.rb +1 -1
- data/lib/head_music/version.rb +1 -1
- data/lib/head_music.rb +50 -46
- metadata +51 -51
- data/lib/head_music/rhythm.rb +0 -3
- /data/lib/head_music/{data → rudiment}/clefs.yml +0 -0
- /data/lib/head_music/{solmizations.yml → rudiment/solmizations.yml} +0 -0
@@ -1,19 +1,19 @@
|
|
1
1
|
# Key signatures are enharmonic when all pitch classes in one are respellings of the pitch classes in the other.
|
2
|
-
class HeadMusic::KeySignature::EnharmonicEquivalence
|
2
|
+
class HeadMusic::Rudiment::KeySignature::EnharmonicEquivalence
|
3
3
|
attr_reader :key_signature
|
4
4
|
|
5
5
|
def self.get(key_signature)
|
6
|
-
key_signature = HeadMusic::KeySignature.get(key_signature)
|
6
|
+
key_signature = HeadMusic::Rudiment::KeySignature.get(key_signature)
|
7
7
|
@enharmonic_equivalences ||= {}
|
8
8
|
@enharmonic_equivalences[key_signature.to_s] ||= new(key_signature)
|
9
9
|
end
|
10
10
|
|
11
11
|
def initialize(key_signature)
|
12
|
-
@key_signature = HeadMusic::KeySignature.get(key_signature)
|
12
|
+
@key_signature = HeadMusic::Rudiment::KeySignature.get(key_signature)
|
13
13
|
end
|
14
14
|
|
15
15
|
def enharmonic_equivalent?(other)
|
16
|
-
other = HeadMusic::KeySignature.get(other)
|
16
|
+
other = HeadMusic::Rudiment::KeySignature.get(other)
|
17
17
|
|
18
18
|
key_signature.pitch_classes.map(&:to_i).sort == other.pitch_classes.map(&:to_i).sort &&
|
19
19
|
key_signature.alterations.map(&:to_s).sort != other.alterations.map(&:to_s).sort
|
@@ -1,5 +1,8 @@
|
|
1
|
+
# A module for music rudiments
|
2
|
+
module HeadMusic::Rudiment; end
|
3
|
+
|
1
4
|
# Represents a key signature.
|
2
|
-
class HeadMusic::KeySignature
|
5
|
+
class HeadMusic::Rudiment::KeySignature
|
3
6
|
attr_reader :tonic_spelling, :scale_type, :scale
|
4
7
|
|
5
8
|
ORDERED_LETTER_NAMES_OF_SHARPS = %w[F C G D A E B].freeze
|
@@ -10,7 +13,7 @@ class HeadMusic::KeySignature
|
|
10
13
|
end
|
11
14
|
|
12
15
|
def self.get(identifier)
|
13
|
-
return identifier if identifier.is_a?(HeadMusic::KeySignature)
|
16
|
+
return identifier if identifier.is_a?(HeadMusic::Rudiment::KeySignature)
|
14
17
|
|
15
18
|
@key_signatures ||= {}
|
16
19
|
tonic_spelling, scale_type_name = identifier.strip.split(/\s/)
|
@@ -23,11 +26,11 @@ class HeadMusic::KeySignature
|
|
23
26
|
delegate :pitches, :pitch_classes, to: :scale
|
24
27
|
|
25
28
|
def initialize(tonic_spelling, scale_type = nil)
|
26
|
-
@tonic_spelling = HeadMusic::Spelling.get(tonic_spelling)
|
27
|
-
@scale_type = HeadMusic::ScaleType.get(scale_type) if scale_type
|
28
|
-
@scale_type ||= HeadMusic::ScaleType.default
|
29
|
+
@tonic_spelling = HeadMusic::Rudiment::Spelling.get(tonic_spelling)
|
30
|
+
@scale_type = HeadMusic::Rudiment::ScaleType.get(scale_type) if scale_type
|
31
|
+
@scale_type ||= HeadMusic::Rudiment::ScaleType.default
|
29
32
|
@scale_type = @scale_type.parent || @scale_type
|
30
|
-
@scale = HeadMusic::Scale.get(@tonic_spelling, @scale_type)
|
33
|
+
@scale = HeadMusic::Rudiment::Scale.get(@tonic_spelling, @scale_type)
|
31
34
|
end
|
32
35
|
|
33
36
|
def spellings
|
@@ -102,6 +105,6 @@ class HeadMusic::KeySignature
|
|
102
105
|
private
|
103
106
|
|
104
107
|
def enharmonic_equivalence
|
105
|
-
@enharmonic_equivalence ||= HeadMusic::KeySignature::EnharmonicEquivalence.get(self)
|
108
|
+
@enharmonic_equivalence ||= HeadMusic::Rudiment::KeySignature::EnharmonicEquivalence.get(self)
|
106
109
|
end
|
107
110
|
end
|
@@ -1,5 +1,8 @@
|
|
1
|
+
# A module for music rudiments
|
2
|
+
module HeadMusic::Rudiment; end
|
3
|
+
|
1
4
|
# Music has seven lette names that are used to identify pitches and pitch classes.
|
2
|
-
class HeadMusic::LetterName
|
5
|
+
class HeadMusic::Rudiment::LetterName
|
3
6
|
NAMES = %w[C D E F G A B].freeze
|
4
7
|
|
5
8
|
NATURAL_PITCH_CLASS_NUMBERS = {
|
@@ -32,7 +35,7 @@ class HeadMusic::LetterName
|
|
32
35
|
|
33
36
|
pitch_class = pitch_class.to_i % 12
|
34
37
|
name = NAMES.detect { |candidate| pitch_class == NATURAL_PITCH_CLASS_NUMBERS[candidate] }
|
35
|
-
name ||= HeadMusic::PitchClass::SHARP_SPELLINGS[pitch_class].first
|
38
|
+
name ||= HeadMusic::Rudiment::PitchClass::SHARP_SPELLINGS[pitch_class].first
|
36
39
|
@letter_names[name] ||= new(name) if NAMES.include?(name)
|
37
40
|
end
|
38
41
|
|
@@ -47,7 +50,7 @@ class HeadMusic::LetterName
|
|
47
50
|
end
|
48
51
|
|
49
52
|
def pitch_class
|
50
|
-
HeadMusic::PitchClass.get(NATURAL_PITCH_CLASS_NUMBERS[name])
|
53
|
+
HeadMusic::Rudiment::PitchClass.get(NATURAL_PITCH_CLASS_NUMBERS[name])
|
51
54
|
end
|
52
55
|
|
53
56
|
def ==(other)
|
@@ -59,15 +62,15 @@ class HeadMusic::LetterName
|
|
59
62
|
end
|
60
63
|
|
61
64
|
def steps_up(num)
|
62
|
-
HeadMusic::LetterName.get(series_ascending[num % NAMES.length])
|
65
|
+
HeadMusic::Rudiment::LetterName.get(series_ascending[num % NAMES.length])
|
63
66
|
end
|
64
67
|
|
65
68
|
def steps_down(num)
|
66
|
-
HeadMusic::LetterName.get(series_descending[num % NAMES.length])
|
69
|
+
HeadMusic::Rudiment::LetterName.get(series_descending[num % NAMES.length])
|
67
70
|
end
|
68
71
|
|
69
72
|
def steps_to(other, direction = :ascending)
|
70
|
-
other = HeadMusic::LetterName.get(other)
|
73
|
+
other = HeadMusic::Rudiment::LetterName.get(other)
|
71
74
|
other_position = other.position
|
72
75
|
if direction == :descending
|
73
76
|
other_position -= NAMES.length if other_position > position
|
@@ -1,5 +1,8 @@
|
|
1
|
+
# A module for music rudiments
|
2
|
+
module HeadMusic::Rudiment; end
|
3
|
+
|
1
4
|
# Meter is the rhythmic size of a measure, such as 4/4 or 6/8
|
2
|
-
class HeadMusic::Meter
|
5
|
+
class HeadMusic::Rudiment::Meter
|
3
6
|
attr_reader :top_number, :bottom_number
|
4
7
|
|
5
8
|
NAMED = {
|
@@ -74,13 +77,13 @@ class HeadMusic::Meter
|
|
74
77
|
end
|
75
78
|
|
76
79
|
def count_unit
|
77
|
-
HeadMusic::RhythmicUnit.for_denominator_value(bottom_number)
|
80
|
+
HeadMusic::Rudiment::RhythmicUnit.for_denominator_value(bottom_number)
|
78
81
|
end
|
79
82
|
|
80
83
|
def beat_unit
|
81
84
|
@beat_unit ||=
|
82
85
|
if compound?
|
83
|
-
HeadMusic::Content::RhythmicValue.new(HeadMusic::RhythmicUnit.for_denominator_value(bottom_number / 2), dots: 1)
|
86
|
+
HeadMusic::Content::RhythmicValue.new(HeadMusic::Rudiment::RhythmicUnit.for_denominator_value(bottom_number / 2), dots: 1)
|
84
87
|
else
|
85
88
|
HeadMusic::Content::RhythmicValue.new(count_unit)
|
86
89
|
end
|
@@ -1,5 +1,8 @@
|
|
1
|
+
# A module for music rudiments
|
2
|
+
module HeadMusic::Rudiment; end
|
3
|
+
|
1
4
|
# A symbol is a mark or sign that signifies a particular rudiment of music
|
2
|
-
class HeadMusic::MusicalSymbol
|
5
|
+
class HeadMusic::Rudiment::MusicalSymbol
|
3
6
|
attr_reader :ascii, :unicode, :html_entity
|
4
7
|
|
5
8
|
def initialize(ascii: nil, unicode: nil, html_entity: nil)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# An enharmonic equivalent pitch is the same frequency spelled differently, such as D# and Eb.
|
2
|
-
class HeadMusic::Pitch::EnharmonicEquivalence
|
2
|
+
class HeadMusic::Rudiment::Pitch::EnharmonicEquivalence
|
3
3
|
def self.get(pitch)
|
4
|
-
pitch = HeadMusic::Pitch.get(pitch)
|
4
|
+
pitch = HeadMusic::Rudiment::Pitch.get(pitch)
|
5
5
|
@enharmonic_equivalences ||= {}
|
6
6
|
@enharmonic_equivalences[pitch.to_s] ||= new(pitch)
|
7
7
|
end
|
@@ -11,11 +11,11 @@ class HeadMusic::Pitch::EnharmonicEquivalence
|
|
11
11
|
delegate :pitch_class, to: :pitch
|
12
12
|
|
13
13
|
def initialize(pitch)
|
14
|
-
@pitch = HeadMusic::Pitch.get(pitch)
|
14
|
+
@pitch = HeadMusic::Rudiment::Pitch.get(pitch)
|
15
15
|
end
|
16
16
|
|
17
17
|
def enharmonic_equivalent?(other)
|
18
|
-
other = HeadMusic::Pitch.get(other)
|
18
|
+
other = HeadMusic::Rudiment::Pitch.get(other)
|
19
19
|
pitch.midi_note_number == other.midi_note_number && pitch.spelling != other.spelling
|
20
20
|
end
|
21
21
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# Octave equivalence is the functional equivalence of pitches with the same spelling separated by one or more octaves.
|
2
|
-
class HeadMusic::Pitch::OctaveEquivalence
|
2
|
+
class HeadMusic::Rudiment::Pitch::OctaveEquivalence
|
3
3
|
def self.get(pitch)
|
4
4
|
@octave_equivalences ||= {}
|
5
5
|
@octave_equivalences[pitch.to_s] ||= new(pitch)
|
@@ -12,7 +12,7 @@ class HeadMusic::Pitch::OctaveEquivalence
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def octave_equivalent?(other)
|
15
|
-
other = HeadMusic::Pitch.get(other)
|
15
|
+
other = HeadMusic::Rudiment::Pitch.get(other)
|
16
16
|
pitch.spelling == other.spelling && pitch.register != other.register
|
17
17
|
end
|
18
18
|
|
@@ -1,5 +1,8 @@
|
|
1
|
+
# A module for music rudiments
|
2
|
+
module HeadMusic::Rudiment; end
|
3
|
+
|
1
4
|
# A pitch is a named frequency represented by a spelling and a register.
|
2
|
-
class HeadMusic::Pitch
|
5
|
+
class HeadMusic::Rudiment::Pitch
|
3
6
|
include Comparable
|
4
7
|
|
5
8
|
attr_reader :spelling, :register
|
@@ -40,7 +43,7 @@ class HeadMusic::Pitch
|
|
40
43
|
end
|
41
44
|
|
42
45
|
def self.from_pitch_class(pitch_class)
|
43
|
-
return nil unless pitch_class.is_a?(HeadMusic::PitchClass)
|
46
|
+
return nil unless pitch_class.is_a?(HeadMusic::Rudiment::PitchClass)
|
44
47
|
|
45
48
|
fetch_or_create(pitch_class.sharp_spelling)
|
46
49
|
end
|
@@ -48,33 +51,33 @@ class HeadMusic::Pitch
|
|
48
51
|
def self.from_name(name)
|
49
52
|
return nil unless name == name.to_s
|
50
53
|
|
51
|
-
fetch_or_create(HeadMusic::Spelling.get(name), HeadMusic::Register.get(name).to_i)
|
54
|
+
fetch_or_create(HeadMusic::Rudiment::Spelling.get(name), HeadMusic::Rudiment::Register.get(name).to_i)
|
52
55
|
end
|
53
56
|
|
54
57
|
def self.from_number(number)
|
55
58
|
return nil unless number == number.to_i
|
56
59
|
|
57
|
-
fetch_or_create(HeadMusic::Spelling.from_number(number), (number.to_i / 12) - 1)
|
60
|
+
fetch_or_create(HeadMusic::Rudiment::Spelling.from_number(number), (number.to_i / 12) - 1)
|
58
61
|
end
|
59
62
|
|
60
63
|
def self.from_number_and_letter(number, letter_name)
|
61
|
-
letter_name = HeadMusic::LetterName.get(letter_name)
|
64
|
+
letter_name = HeadMusic::Rudiment::LetterName.get(letter_name)
|
62
65
|
natural_letter_pitch = natural_letter_pitch(number, letter_name)
|
63
|
-
alteration_interval = natural_letter_pitch.smallest_interval_to(HeadMusic::PitchClass.get(number))
|
64
|
-
alteration = HeadMusic::Alteration.by(:semitones, alteration_interval) if alteration_interval != 0
|
65
|
-
spelling = HeadMusic::Spelling.fetch_or_create(letter_name, alteration)
|
66
|
+
alteration_interval = natural_letter_pitch.smallest_interval_to(HeadMusic::Rudiment::PitchClass.get(number))
|
67
|
+
alteration = HeadMusic::Rudiment::Alteration.by(:semitones, alteration_interval) if alteration_interval != 0
|
68
|
+
spelling = HeadMusic::Rudiment::Spelling.fetch_or_create(letter_name, alteration)
|
66
69
|
fetch_or_create(spelling, natural_letter_pitch.register)
|
67
70
|
end
|
68
71
|
|
69
72
|
def self.natural_letter_pitch(number, letter_name)
|
70
|
-
natural_letter_pitch = get(HeadMusic::LetterName.get(letter_name).pitch_class)
|
73
|
+
natural_letter_pitch = get(HeadMusic::Rudiment::LetterName.get(letter_name).pitch_class)
|
71
74
|
natural_letter_pitch += 12 while (number.to_i - natural_letter_pitch.to_i) >= 6
|
72
75
|
natural_letter_pitch -= 12 while (number.to_i - natural_letter_pitch.to_i) <= -6
|
73
76
|
get(natural_letter_pitch)
|
74
77
|
end
|
75
78
|
|
76
79
|
def self.fetch_or_create(spelling, register = nil)
|
77
|
-
register ||= HeadMusic::Register::DEFAULT
|
80
|
+
register ||= HeadMusic::Rudiment::Register::DEFAULT
|
78
81
|
return unless spelling && (-1..9).cover?(register)
|
79
82
|
|
80
83
|
@pitches ||= {}
|
@@ -83,7 +86,7 @@ class HeadMusic::Pitch
|
|
83
86
|
end
|
84
87
|
|
85
88
|
def initialize(spelling, register)
|
86
|
-
@spelling = HeadMusic::Spelling.get(spelling.to_s)
|
89
|
+
@spelling = HeadMusic::Rudiment::Spelling.get(spelling.to_s)
|
87
90
|
@register = register.to_i
|
88
91
|
end
|
89
92
|
|
@@ -111,35 +114,35 @@ class HeadMusic::Pitch
|
|
111
114
|
end
|
112
115
|
|
113
116
|
def natural
|
114
|
-
HeadMusic::Pitch.get(to_s.gsub(HeadMusic::Alteration.matcher, ""))
|
117
|
+
HeadMusic::Rudiment::Pitch.get(to_s.gsub(HeadMusic::Rudiment::Alteration.matcher, ""))
|
115
118
|
end
|
116
119
|
|
117
120
|
def +(other)
|
118
|
-
if other.is_a?(HeadMusic::DiatonicInterval)
|
121
|
+
if other.is_a?(HeadMusic::Analysis::DiatonicInterval)
|
119
122
|
# return a pitch
|
120
123
|
other.above(self)
|
121
124
|
else
|
122
125
|
# assume value represents an interval in semitones and return another pitch
|
123
|
-
HeadMusic::Pitch.get(to_i + other.to_i)
|
126
|
+
HeadMusic::Rudiment::Pitch.get(to_i + other.to_i)
|
124
127
|
end
|
125
128
|
end
|
126
129
|
|
127
130
|
def -(other)
|
128
131
|
case other
|
129
|
-
when HeadMusic::DiatonicInterval
|
132
|
+
when HeadMusic::Analysis::DiatonicInterval
|
130
133
|
# return a pitch
|
131
134
|
other.below(self)
|
132
|
-
when HeadMusic::Pitch
|
135
|
+
when HeadMusic::Rudiment::Pitch
|
133
136
|
# return an interval
|
134
|
-
HeadMusic::ChromaticInterval.get(to_i - other.to_i)
|
137
|
+
HeadMusic::Rudiment::ChromaticInterval.get(to_i - other.to_i)
|
135
138
|
else
|
136
139
|
# assume value represents an interval in semitones and return another pitch
|
137
|
-
HeadMusic::Pitch.get(to_i - other.to_i)
|
140
|
+
HeadMusic::Rudiment::Pitch.get(to_i - other.to_i)
|
138
141
|
end
|
139
142
|
end
|
140
143
|
|
141
144
|
def ==(other)
|
142
|
-
other = HeadMusic::Pitch.get(other)
|
145
|
+
other = HeadMusic::Rudiment::Pitch.get(other)
|
143
146
|
to_s == other.to_s
|
144
147
|
end
|
145
148
|
|
@@ -148,11 +151,11 @@ class HeadMusic::Pitch
|
|
148
151
|
end
|
149
152
|
|
150
153
|
def scale(scale_type_name = nil)
|
151
|
-
HeadMusic::Scale.get(self, scale_type_name)
|
154
|
+
HeadMusic::Rudiment::Scale.get(self, scale_type_name)
|
152
155
|
end
|
153
156
|
|
154
157
|
def natural_steps(num_steps)
|
155
|
-
HeadMusic::Pitch.get([target_letter_name(num_steps), register + octaves_delta(num_steps)].join)
|
158
|
+
HeadMusic::Rudiment::Pitch.get([target_letter_name(num_steps), register + octaves_delta(num_steps)].join)
|
156
159
|
end
|
157
160
|
|
158
161
|
def frequency
|
@@ -160,7 +163,7 @@ class HeadMusic::Pitch
|
|
160
163
|
end
|
161
164
|
|
162
165
|
def steps_to(other)
|
163
|
-
other = HeadMusic::Pitch.get(other)
|
166
|
+
other = HeadMusic::Rudiment::Pitch.get(other)
|
164
167
|
letter_name_steps_to(other) + 7 * octave_changes_to(other)
|
165
168
|
end
|
166
169
|
|
@@ -181,15 +184,15 @@ class HeadMusic::Pitch
|
|
181
184
|
end
|
182
185
|
|
183
186
|
def enharmonic_equivalence
|
184
|
-
@enharmonic_equivalence ||= HeadMusic::Pitch::EnharmonicEquivalence.get(self)
|
187
|
+
@enharmonic_equivalence ||= HeadMusic::Rudiment::Pitch::EnharmonicEquivalence.get(self)
|
185
188
|
end
|
186
189
|
|
187
190
|
def octave_equivalence
|
188
|
-
@octave_equivalence ||= HeadMusic::Pitch::OctaveEquivalence.get(self)
|
191
|
+
@octave_equivalence ||= HeadMusic::Rudiment::Pitch::OctaveEquivalence.get(self)
|
189
192
|
end
|
190
193
|
|
191
194
|
def tuning
|
192
|
-
@tuning ||= HeadMusic::Tuning.new
|
195
|
+
@tuning ||= HeadMusic::Rudiment::Tuning.new
|
193
196
|
end
|
194
197
|
|
195
198
|
def octaves_delta(num_steps)
|
@@ -216,12 +219,12 @@ class HeadMusic::Pitch
|
|
216
219
|
end
|
217
220
|
|
218
221
|
def helmholtz_letter_name
|
219
|
-
return spelling.to_s.downcase if HeadMusic::Register.get(register).helmholtz_case == :lower
|
222
|
+
return spelling.to_s.downcase if HeadMusic::Rudiment::Register.get(register).helmholtz_case == :lower
|
220
223
|
|
221
224
|
spelling.to_s
|
222
225
|
end
|
223
226
|
|
224
227
|
def helmholtz_marks
|
225
|
-
HeadMusic::Register.get(register).helmholtz_marks
|
228
|
+
HeadMusic::Rudiment::Register.get(register).helmholtz_marks
|
226
229
|
end
|
227
230
|
end
|
@@ -1,5 +1,8 @@
|
|
1
|
+
# A module for music rudiments
|
2
|
+
module HeadMusic::Rudiment; end
|
3
|
+
|
1
4
|
# A pitch class is a set of pitches separated by octaves.
|
2
|
-
class HeadMusic::PitchClass
|
5
|
+
class HeadMusic::Rudiment::PitchClass
|
3
6
|
include Comparable
|
4
7
|
|
5
8
|
attr_reader :number, :spelling
|
@@ -11,8 +14,8 @@ class HeadMusic::PitchClass
|
|
11
14
|
|
12
15
|
def self.get(identifier)
|
13
16
|
@pitch_classes ||= {}
|
14
|
-
if HeadMusic::Spelling.matching_string(identifier)
|
15
|
-
spelling = HeadMusic::Spelling.get(identifier)
|
17
|
+
if HeadMusic::Rudiment::Spelling.matching_string(identifier)
|
18
|
+
spelling = HeadMusic::Rudiment::Spelling.get(identifier)
|
16
19
|
number = spelling.pitch_class.to_i
|
17
20
|
end
|
18
21
|
number ||= identifier.to_i % 12
|
@@ -48,23 +51,23 @@ class HeadMusic::PitchClass
|
|
48
51
|
end
|
49
52
|
|
50
53
|
def smart_spelling(max_sharps_in_major_key_signature: 6)
|
51
|
-
sharp_key = HeadMusic::KeySignature.get(sharp_spelling)
|
52
|
-
return HeadMusic::Spelling.get(sharp_spelling) if sharp_key.num_sharps <= max_sharps_in_major_key_signature
|
54
|
+
sharp_key = HeadMusic::Rudiment::KeySignature.get(sharp_spelling)
|
55
|
+
return HeadMusic::Rudiment::Spelling.get(sharp_spelling) if sharp_key.num_sharps <= max_sharps_in_major_key_signature
|
53
56
|
|
54
|
-
flat_key = HeadMusic::KeySignature.get(flat_spelling)
|
55
|
-
return HeadMusic::Spelling.get(flat_spelling) if flat_key.num_sharps <= max_sharps_in_major_key_signature
|
57
|
+
flat_key = HeadMusic::Rudiment::KeySignature.get(flat_spelling)
|
58
|
+
return HeadMusic::Rudiment::Spelling.get(flat_spelling) if flat_key.num_sharps <= max_sharps_in_major_key_signature
|
56
59
|
|
57
|
-
HeadMusic::Spelling.get(flatter_spelling)
|
60
|
+
HeadMusic::Rudiment::Spelling.get(flatter_spelling)
|
58
61
|
end
|
59
62
|
|
60
63
|
# Pass in the number of semitones
|
61
64
|
def +(other)
|
62
|
-
HeadMusic::PitchClass.get(to_i + other.to_i)
|
65
|
+
HeadMusic::Rudiment::PitchClass.get(to_i + other.to_i)
|
63
66
|
end
|
64
67
|
|
65
68
|
# Pass in the number of semitones
|
66
69
|
def -(other)
|
67
|
-
HeadMusic::PitchClass.get(to_i - other.to_i)
|
70
|
+
HeadMusic::Rudiment::PitchClass.get(to_i - other.to_i)
|
68
71
|
end
|
69
72
|
|
70
73
|
def ==(other)
|
@@ -79,7 +82,7 @@ class HeadMusic::PitchClass
|
|
79
82
|
def intervals_to(other)
|
80
83
|
delta = other.to_i - to_i
|
81
84
|
inverse = delta.positive? ? delta - 12 : delta + 12
|
82
|
-
[delta, inverse].sort_by(&:abs).map { |interval| HeadMusic::ChromaticInterval.get(interval) }
|
85
|
+
[delta, inverse].sort_by(&:abs).map { |interval| HeadMusic::Rudiment::ChromaticInterval.get(interval) }
|
83
86
|
end
|
84
87
|
|
85
88
|
def smallest_interval_to(other)
|
@@ -1,6 +1,9 @@
|
|
1
|
+
# A module for music rudiments
|
2
|
+
module HeadMusic::Rudiment; end
|
3
|
+
|
1
4
|
# A reference pitch has a pitch and a frequency
|
2
5
|
# With no arguments, it assumes that A4 = 440.0 Hz
|
3
|
-
class HeadMusic::ReferencePitch
|
6
|
+
class HeadMusic::Rudiment::ReferencePitch
|
4
7
|
include HeadMusic::Named
|
5
8
|
|
6
9
|
DEFAULT_PITCH_NAME = "A4"
|
@@ -81,7 +84,7 @@ class HeadMusic::ReferencePitch
|
|
81
84
|
|
82
85
|
def initialize(name = DEFAULT_REFERENCE_PITCH_NAME)
|
83
86
|
record = named_reference_pitch_record_for_name(name)
|
84
|
-
@pitch = HeadMusic::Pitch.get(record.fetch(:pitch, DEFAULT_PITCH_NAME))
|
87
|
+
@pitch = HeadMusic::Rudiment::Pitch.get(record.fetch(:pitch, DEFAULT_PITCH_NAME))
|
85
88
|
@frequency = record.fetch(:frequency, DEFAULT_FREQUENCY)
|
86
89
|
initialize_keys_from_record(record)
|
87
90
|
end
|
@@ -1,9 +1,12 @@
|
|
1
|
+
# A module for music rudiments
|
2
|
+
module HeadMusic::Rudiment; end
|
3
|
+
|
1
4
|
# The register is a numeric octave identifier used in scientific pitch notation.
|
2
5
|
#
|
3
6
|
# A pitch is a spelling plus a register. For example, C4 is middle C and C5 is the C one octave higher.
|
4
7
|
# The number changes between the letter names B and C regardless of sharps and flats,
|
5
8
|
# so as an extreme example, Cb5 is actually a semitone below B#4.
|
6
|
-
class HeadMusic::Register
|
9
|
+
class HeadMusic::Rudiment::Register
|
7
10
|
include Comparable
|
8
11
|
|
9
12
|
DEFAULT = 4
|
@@ -21,9 +24,9 @@ class HeadMusic::Register
|
|
21
24
|
end
|
22
25
|
|
23
26
|
def self.from_name(string)
|
24
|
-
return unless string.to_s.match?(HeadMusic::Spelling::MATCHER)
|
27
|
+
return unless string.to_s.match?(HeadMusic::Rudiment::Spelling::MATCHER)
|
25
28
|
|
26
|
-
_letter, _sign, register_string = string.to_s.match(HeadMusic::Spelling::MATCHER).captures
|
29
|
+
_letter, _sign, register_string = string.to_s.match(HeadMusic::Rudiment::Spelling::MATCHER).captures
|
27
30
|
@registers ||= {}
|
28
31
|
@registers[register_string.to_i] ||= new(register_string.to_i) if register_string
|
29
32
|
end
|
@@ -1,5 +1,8 @@
|
|
1
|
+
# A module for music rudiments
|
2
|
+
module HeadMusic::Rudiment; end
|
3
|
+
|
1
4
|
# A rhythmic unit is a rudiment of duration consisting of doublings and divisions of a whole note.
|
2
|
-
class HeadMusic::RhythmicUnit
|
5
|
+
class HeadMusic::Rudiment::RhythmicUnit
|
3
6
|
include HeadMusic::Named
|
4
7
|
|
5
8
|
MULTIPLES = ["whole", "double whole", "longa", "maxima"].freeze
|
@@ -35,7 +38,7 @@ class HeadMusic::RhythmicUnit
|
|
35
38
|
end
|
36
39
|
|
37
40
|
def ticks
|
38
|
-
HeadMusic::Rhythm::PPQN * 4 * relative_value
|
41
|
+
HeadMusic::Rudiment::Rhythm::PPQN * 4 * relative_value
|
39
42
|
end
|
40
43
|
|
41
44
|
def notehead
|
@@ -1,11 +1,14 @@
|
|
1
|
+
# A module for music rudiments
|
2
|
+
module HeadMusic::Rudiment; end
|
3
|
+
|
1
4
|
# A scale contains ordered pitches starting at a tonal center.
|
2
|
-
class HeadMusic::Scale
|
5
|
+
class HeadMusic::Rudiment::Scale
|
3
6
|
SCALE_REGEX = /^[A-G][#b]?\s+\w+$/
|
4
7
|
|
5
8
|
def self.get(root_pitch, scale_type = nil)
|
6
9
|
root_pitch, scale_type = root_pitch.split(/\s+/) if root_pitch.is_a?(String) && scale_type =~ SCALE_REGEX
|
7
|
-
root_pitch = HeadMusic::Pitch.get(root_pitch)
|
8
|
-
scale_type = HeadMusic::ScaleType.get(scale_type || :major)
|
10
|
+
root_pitch = HeadMusic::Rudiment::Pitch.get(root_pitch)
|
11
|
+
scale_type = HeadMusic::Rudiment::ScaleType.get(scale_type || :major)
|
9
12
|
@scales ||= {}
|
10
13
|
hash_key = HeadMusic::Utilities::HashKey.for(
|
11
14
|
[root_pitch, scale_type].join(" ").gsub(/#|♯/, "sharp").gsub(/(\w)[b♭]/, '\\1flat')
|
@@ -18,8 +21,8 @@ class HeadMusic::Scale
|
|
18
21
|
attr_reader :root_pitch, :scale_type
|
19
22
|
|
20
23
|
def initialize(root_pitch, scale_type)
|
21
|
-
@root_pitch = HeadMusic::Pitch.get(root_pitch)
|
22
|
-
@scale_type = HeadMusic::ScaleType.get(scale_type)
|
24
|
+
@root_pitch = HeadMusic::Rudiment::Pitch.get(root_pitch)
|
25
|
+
@scale_type = HeadMusic::Rudiment::ScaleType.get(scale_type)
|
23
26
|
end
|
24
27
|
|
25
28
|
def pitches(direction: :ascending, octaves: 1)
|
@@ -80,7 +83,7 @@ class HeadMusic::Scale
|
|
80
83
|
end
|
81
84
|
|
82
85
|
def parent_scale_pitches
|
83
|
-
HeadMusic::Scale.get(root_pitch, scale_type.parent_name).pitches if scale_type.parent
|
86
|
+
HeadMusic::Rudiment::Scale.get(root_pitch, scale_type.parent_name).pitches if scale_type.parent
|
84
87
|
end
|
85
88
|
|
86
89
|
def parent_scale_pitch_for(semitones_from_root)
|
@@ -92,7 +95,7 @@ class HeadMusic::Scale
|
|
92
95
|
def pitch_for_step(step, semitones_from_root, direction)
|
93
96
|
pitch_number = root_pitch_number + semitones_from_root
|
94
97
|
letter_name = letter_for_step(step, semitones_from_root, direction)
|
95
|
-
HeadMusic::Pitch.from_number_and_letter(pitch_number, letter_name)
|
98
|
+
HeadMusic::Rudiment::Pitch.from_number_and_letter(pitch_number, letter_name)
|
96
99
|
end
|
97
100
|
|
98
101
|
def letter_for_step(step, semitones_from_root, direction)
|
@@ -117,11 +120,11 @@ class HeadMusic::Scale
|
|
117
120
|
def flat_letter_for_step(semitones_from_root)
|
118
121
|
return unless root_pitch.flat?
|
119
122
|
|
120
|
-
HeadMusic::PitchClass::FLAT_SPELLINGS[pitch_class_number(semitones_from_root)]
|
123
|
+
HeadMusic::Rudiment::PitchClass::FLAT_SPELLINGS[pitch_class_number(semitones_from_root)]
|
121
124
|
end
|
122
125
|
|
123
126
|
def sharp_letter_for_step(semitones_from_root)
|
124
|
-
HeadMusic::PitchClass::SHARP_SPELLINGS[pitch_class_number(semitones_from_root)]
|
127
|
+
HeadMusic::Rudiment::PitchClass::SHARP_SPELLINGS[pitch_class_number(semitones_from_root)]
|
125
128
|
end
|
126
129
|
|
127
130
|
def pitch_class_number(semitones_from_root)
|
@@ -1,6 +1,9 @@
|
|
1
|
+
# A module for music rudiments
|
2
|
+
module HeadMusic::Rudiment; end
|
3
|
+
|
1
4
|
# A scale degree is a number indicating the ordinality of the spelling in the key.
|
2
5
|
# TODO: Rewrite to accept a tonal_center and a scale type.
|
3
|
-
class HeadMusic::ScaleDegree
|
6
|
+
class HeadMusic::Rudiment::ScaleDegree
|
4
7
|
include Comparable
|
5
8
|
|
6
9
|
NAME_FOR_DIATONIC_DEGREE = [nil, "tonic", "supertonic", "mediant", "subdominant", "dominant", "submediant"].freeze
|
@@ -12,7 +15,7 @@ class HeadMusic::ScaleDegree
|
|
12
15
|
|
13
16
|
def initialize(key_signature, spelling)
|
14
17
|
@key_signature = key_signature
|
15
|
-
@spelling = HeadMusic::Spelling.get(spelling)
|
18
|
+
@spelling = HeadMusic::Rudiment::Spelling.get(spelling)
|
16
19
|
end
|
17
20
|
|
18
21
|
def degree
|
@@ -23,7 +26,7 @@ class HeadMusic::ScaleDegree
|
|
23
26
|
spelling_alteration_semitones = spelling.alteration&.semitones || 0
|
24
27
|
usual_sign_semitones = scale_degree_usual_spelling.alteration&.semitones || 0
|
25
28
|
delta = spelling_alteration_semitones - usual_sign_semitones
|
26
|
-
HeadMusic::Alteration.by(:semitones, delta) if delta != 0
|
29
|
+
HeadMusic::Rudiment::Alteration.by(:semitones, delta) if delta != 0
|
27
30
|
end
|
28
31
|
|
29
32
|
def alteration_semitones
|
@@ -35,7 +38,7 @@ class HeadMusic::ScaleDegree
|
|
35
38
|
end
|
36
39
|
|
37
40
|
def <=>(other)
|
38
|
-
if other.is_a?(HeadMusic::ScaleDegree)
|
41
|
+
if other.is_a?(HeadMusic::Rudiment::ScaleDegree)
|
39
42
|
[degree, alteration_semitones] <=> [other.degree, other.alteration_semitones]
|
40
43
|
else
|
41
44
|
# TODO: Improve this
|
@@ -53,6 +56,6 @@ class HeadMusic::ScaleDegree
|
|
53
56
|
private
|
54
57
|
|
55
58
|
def scale_degree_usual_spelling
|
56
|
-
HeadMusic::Spelling.get(scale.spellings[degree - 1])
|
59
|
+
HeadMusic::Rudiment::Spelling.get(scale.spellings[degree - 1])
|
57
60
|
end
|
58
61
|
end
|
@@ -1,5 +1,8 @@
|
|
1
|
+
# A module for music rudiments
|
2
|
+
module HeadMusic::Rudiment; end
|
3
|
+
|
1
4
|
# A ScaleType represents a particular scale pattern, such as major, lydian, or minor pentatonic.
|
2
|
-
class HeadMusic::ScaleType
|
5
|
+
class HeadMusic::Rudiment::ScaleType
|
3
6
|
H = 1 # whole step
|
4
7
|
W = 2 # half step
|
5
8
|
|
@@ -1,6 +1,9 @@
|
|
1
|
+
# A module for music rudiments
|
2
|
+
module HeadMusic::Rudiment; end
|
3
|
+
|
1
4
|
# A scale degree is a number indicating the ordinality of the spelling in the key signature.
|
2
5
|
# TODO: Rewrite to accept a tonal_center and a scale type.
|
3
|
-
class HeadMusic::Solmization
|
6
|
+
class HeadMusic::Rudiment::Solmization
|
4
7
|
include HeadMusic::Named
|
5
8
|
|
6
9
|
DEFAULT_SOLMIZATION = "solfège"
|