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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/Gemfile +1 -1
  4. data/lib/head_music/{circle.rb → analysis/circle.rb} +9 -6
  5. data/lib/head_music/{diatonic_interval → analysis/diatonic_interval}/category.rb +1 -1
  6. data/lib/head_music/{diatonic_interval → analysis/diatonic_interval}/naming.rb +6 -6
  7. data/lib/head_music/{diatonic_interval → analysis/diatonic_interval}/parser.rb +4 -4
  8. data/lib/head_music/{diatonic_interval → analysis/diatonic_interval}/semitones.rb +4 -4
  9. data/lib/head_music/{diatonic_interval → analysis/diatonic_interval}/size.rb +1 -1
  10. data/lib/head_music/{diatonic_interval.rb → analysis/diatonic_interval.rb} +19 -16
  11. data/lib/head_music/{harmonic_interval.rb → analysis/harmonic_interval.rb} +5 -2
  12. data/lib/head_music/{interval_cycle.rb → analysis/interval_cycle.rb} +12 -9
  13. data/lib/head_music/{melodic_interval.rb → analysis/melodic_interval.rb} +7 -4
  14. data/lib/head_music/{motion.rb → analysis/motion.rb} +6 -3
  15. data/lib/head_music/{pitch_class_set.rb → analysis/pitch_class_set.rb} +5 -2
  16. data/lib/head_music/{pitch_set.rb → analysis/pitch_set.rb} +14 -11
  17. data/lib/head_music/{sonority.rb → analysis/sonority.rb} +7 -4
  18. data/lib/head_music/content/bar.rb +2 -2
  19. data/lib/head_music/content/composition.rb +3 -3
  20. data/lib/head_music/content/note.rb +1 -1
  21. data/lib/head_music/content/placement.rb +1 -1
  22. data/lib/head_music/content/position.rb +1 -1
  23. data/lib/head_music/content/rhythmic_value.rb +3 -3
  24. data/lib/head_music/{staff.rb → content/staff.rb} +6 -3
  25. data/lib/head_music/content/voice.rb +2 -2
  26. data/lib/head_music/{instrument.rb → instruments/instrument.rb} +10 -7
  27. data/lib/head_music/{data → instruments}/instrument_families.yml +49 -0
  28. data/lib/head_music/{instrument_family.rb → instruments/instrument_family.rb} +5 -2
  29. data/lib/head_music/{data → instruments}/instruments.yml +116 -0
  30. data/lib/head_music/{instrument → instruments}/staff.rb +5 -2
  31. data/lib/head_music/{instrument → instruments}/staff_scheme.rb +7 -2
  32. data/lib/head_music/{instrument → instruments}/variant.rb +6 -3
  33. data/lib/head_music/locales/en.yml +22 -0
  34. data/lib/head_music/{alteration.rb → rudiment/alteration.rb} +9 -6
  35. data/lib/head_music/{chromatic_interval.rb → rudiment/chromatic_interval.rb} +7 -4
  36. data/lib/head_music/{clef.rb → rudiment/clef.rb} +7 -4
  37. data/lib/head_music/{consonance.rb → rudiment/consonance.rb} +4 -1
  38. data/lib/head_music/{key_signature → rudiment/key_signature}/enharmonic_equivalence.rb +4 -4
  39. data/lib/head_music/{key_signature.rb → rudiment/key_signature.rb} +10 -7
  40. data/lib/head_music/{letter_name.rb → rudiment/letter_name.rb} +9 -6
  41. data/lib/head_music/{meter.rb → rudiment/meter.rb} +6 -3
  42. data/lib/head_music/{musical_symbol.rb → rudiment/musical_symbol.rb} +4 -1
  43. data/lib/head_music/{pitch → rudiment/pitch}/enharmonic_equivalence.rb +4 -4
  44. data/lib/head_music/{pitch → rudiment/pitch}/octave_equivalence.rb +2 -2
  45. data/lib/head_music/{pitch.rb → rudiment/pitch.rb} +30 -27
  46. data/lib/head_music/{pitch_class.rb → rudiment/pitch_class.rb} +14 -11
  47. data/lib/head_music/{quality.rb → rudiment/quality.rb} +4 -1
  48. data/lib/head_music/{reference_pitch.rb → rudiment/reference_pitch.rb} +5 -2
  49. data/lib/head_music/{register.rb → rudiment/register.rb} +6 -3
  50. data/lib/head_music/rudiment/rhythm.rb +6 -0
  51. data/lib/head_music/{rhythmic_unit.rb → rudiment/rhythmic_unit.rb} +5 -2
  52. data/lib/head_music/{scale.rb → rudiment/scale.rb} +12 -9
  53. data/lib/head_music/{scale_degree.rb → rudiment/scale_degree.rb} +8 -5
  54. data/lib/head_music/{scale_type.rb → rudiment/scale_type.rb} +4 -1
  55. data/lib/head_music/{solmization.rb → rudiment/solmization.rb} +4 -1
  56. data/lib/head_music/{spelling.rb → rudiment/spelling.rb} +20 -17
  57. data/lib/head_music/{tuning.rb → rudiment/tuning.rb} +6 -3
  58. data/lib/head_music/style/annotation.rb +6 -6
  59. data/lib/head_music/style/guidelines/consonant_climax.rb +4 -4
  60. data/lib/head_music/style/guidelines/diatonic.rb +1 -1
  61. data/lib/head_music/style/guidelines/step_out_of_unison.rb +1 -1
  62. data/lib/head_music/version.rb +1 -1
  63. data/lib/head_music.rb +50 -46
  64. metadata +51 -51
  65. data/lib/head_music/rhythm.rb +0 -3
  66. /data/lib/head_music/{data → rudiment}/clefs.yml +0 -0
  67. /data/lib/head_music/{solmizations.yml → rudiment/solmizations.yml} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 439ca8119659028d43f890f43e29444ea74331cb31d24815b884a72f2a6ca605
4
- data.tar.gz: 95fef4618cb6509beb136d71a3479503ea21baabe3f667cb5573fca0a2aad2c6
3
+ metadata.gz: 4e3d6ab19fbe0d2fb36ef83bd77eb6e029af7e1ce7e0c78b40bdf0945c114a64
4
+ data.tar.gz: 7392a202e8e2beeb1582116592d99ec2b61ca108227812c335b145ee1664d4d3
5
5
  SHA512:
6
- metadata.gz: c8ab71c5d885903398df2cd6be94be41e64df4eaea057843882f4693453bc8116576957fff07ce870e2d5b5c255a14dc58a8985c7bdbc3add88dbe1ca784f0f4
7
- data.tar.gz: 73ef33e9f539baf59412e511f755819e67ac54177bcd9cd642a21347e11d38bcef6c8d8df918f41dfc5103def3e1fb99abf80a4b69cc084be8459c681cff1c5e
6
+ metadata.gz: c53c0f8a7bb12f7891aa331ce14a8746d89732b6f04dc92aa3793ec22f1d0ac4bcba0662d423f5bc82a553f5c97548b4d951e0a369e8bf809f8b162919211359
7
+ data.tar.gz: 3a92eb3616549a5efbbea45f239241262cb82f704dc78bfe64e9a4943e488389f6f9c95d5b169d813615ad8678e5bf11c44c1bf62b95d67d996a80801ef4a4fe
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.2.2
1
+ 3.3.0
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- ruby "3.2.2"
3
+ ruby "3.3.0"
4
4
 
5
5
  # Specify your gem's dependencies in head_music.gemspec
6
6
  gemspec
@@ -1,7 +1,10 @@
1
- require "head_music/interval_cycle"
1
+ require "head_music/analysis/interval_cycle"
2
+
3
+ # A module for musical analysis
4
+ module HeadMusic::Analysis; end
2
5
 
3
6
  # A Circle of Fifths or Fourths shows relationships between pitch classes
4
- class HeadMusic::Circle < HeadMusic::IntervalCycle
7
+ class HeadMusic::Analysis::Circle < HeadMusic::Analysis::IntervalCycle
5
8
  def self.of_fifths
6
9
  get(:perfect_fifth)
7
10
  end
@@ -12,20 +15,20 @@ class HeadMusic::Circle < HeadMusic::IntervalCycle
12
15
 
13
16
  def self.get(interval = :perfect_fifth)
14
17
  @circles ||= {}
15
- diatonic_interval = HeadMusic::DiatonicInterval.get(interval)
18
+ diatonic_interval = HeadMusic::Analysis::DiatonicInterval.get(interval)
16
19
  @circles[interval] ||= new(interval: diatonic_interval, starting_pitch: "C4")
17
20
  end
18
21
 
19
22
  def index(pitch_class)
20
- pitch_classes.index(HeadMusic::Spelling.get(pitch_class).pitch_class)
23
+ pitch_classes.index(HeadMusic::Rudiment::Spelling.get(pitch_class).pitch_class)
21
24
  end
22
25
 
23
26
  def key_signatures_up
24
- spellings_up.map { |spelling| HeadMusic::KeySignature.new(spelling) }
27
+ spellings_up.map { |spelling| HeadMusic::Rudiment::KeySignature.new(spelling) }
25
28
  end
26
29
 
27
30
  def key_signatures_down
28
- spellings_down.map { |spelling| HeadMusic::KeySignature.new(spelling) }
31
+ spellings_down.map { |spelling| HeadMusic::Rudiment::KeySignature.new(spelling) }
29
32
  end
30
33
 
31
34
  def spellings_up
@@ -1,5 +1,5 @@
1
1
  # Accepts the letter name count between two notes and categorizes the interval
2
- class HeadMusic::DiatonicInterval::Category
2
+ class HeadMusic::Analysis::DiatonicInterval::Category
3
3
  attr_reader :number
4
4
 
5
5
  def initialize(number)
@@ -1,8 +1,8 @@
1
1
  # Accepts a number and number of semitones and privides the naming methods.
2
- class HeadMusic::DiatonicInterval::Naming
3
- QUALITY_SEMITONES = HeadMusic::DiatonicInterval::QUALITY_SEMITONES
4
- NUMBER_NAMES = HeadMusic::DiatonicInterval::NUMBER_NAMES
5
- NAME_SUFFIXES = HeadMusic::DiatonicInterval::NAME_SUFFIXES
2
+ class HeadMusic::Analysis::DiatonicInterval::Naming
3
+ QUALITY_SEMITONES = HeadMusic::Analysis::DiatonicInterval::QUALITY_SEMITONES
4
+ NUMBER_NAMES = HeadMusic::Analysis::DiatonicInterval::NUMBER_NAMES
5
+ NAME_SUFFIXES = HeadMusic::Analysis::DiatonicInterval::NAME_SUFFIXES
6
6
 
7
7
  attr_reader :number, :semitones
8
8
 
@@ -23,7 +23,7 @@ class HeadMusic::DiatonicInterval::Naming
23
23
  starting_quality = QUALITY_SEMITONES[simple_number_name.to_sym].keys.first
24
24
  delta = simple_semitones - (QUALITY_SEMITONES[simple_number_name.to_sym][starting_quality] % 12)
25
25
  delta -= 12 while delta >= 6
26
- HeadMusic::Quality.from(starting_quality, delta)
26
+ HeadMusic::Rudiment::Quality.from(starting_quality, delta)
27
27
  end
28
28
 
29
29
  def simple_number_name
@@ -60,7 +60,7 @@ class HeadMusic::DiatonicInterval::Naming
60
60
  end
61
61
 
62
62
  def quality
63
- @quality ||= HeadMusic::Quality.get(quality_name)
63
+ @quality ||= HeadMusic::Rudiment::Quality.get(quality_name)
64
64
  end
65
65
 
66
66
  def octaves
@@ -1,5 +1,5 @@
1
- class HeadMusic::DiatonicInterval::Parser
2
- NUMBER_NAMES = HeadMusic::DiatonicInterval::NUMBER_NAMES
1
+ class HeadMusic::Analysis::DiatonicInterval::Parser
2
+ NUMBER_NAMES = HeadMusic::Analysis::DiatonicInterval::NUMBER_NAMES
3
3
 
4
4
  attr_reader :identifier
5
5
 
@@ -24,7 +24,7 @@ class HeadMusic::DiatonicInterval::Parser
24
24
  end
25
25
 
26
26
  def higher_letter
27
- HeadMusic::Pitch.middle_c.letter_name.steps_up(steps)
27
+ HeadMusic::Rudiment::Pitch.middle_c.letter_name.steps_up(steps)
28
28
  end
29
29
 
30
30
  def expand(identifier)
@@ -36,7 +36,7 @@ class HeadMusic::DiatonicInterval::Parser
36
36
  end
37
37
 
38
38
  def quality_abbreviations
39
- HeadMusic::DiatonicInterval::QUALITY_ABBREVIATIONS
39
+ HeadMusic::Analysis::DiatonicInterval::QUALITY_ABBREVIATIONS
40
40
  end
41
41
 
42
42
  def quality_for(abbreviation)
@@ -1,6 +1,6 @@
1
1
  # Accepts a name and a quality and returns the number of semitones
2
- class HeadMusic::DiatonicInterval::Semitones
3
- QUALITY_SEMITONES = HeadMusic::DiatonicInterval::QUALITY_SEMITONES
2
+ class HeadMusic::Analysis::DiatonicInterval::Semitones
3
+ QUALITY_SEMITONES = HeadMusic::Analysis::DiatonicInterval::QUALITY_SEMITONES
4
4
 
5
5
  attr_reader :count
6
6
 
@@ -28,9 +28,9 @@ class HeadMusic::DiatonicInterval::Semitones
28
28
 
29
29
  def self._degree_quality_modifications(quality)
30
30
  if quality == :perfect
31
- HeadMusic::Quality::PERFECT_INTERVAL_MODIFICATION.invert
31
+ HeadMusic::Rudiment::Quality::PERFECT_INTERVAL_MODIFICATION.invert
32
32
  else
33
- HeadMusic::Quality::MAJOR_INTERVAL_MODIFICATION.invert
33
+ HeadMusic::Rudiment::Quality::MAJOR_INTERVAL_MODIFICATION.invert
34
34
  end
35
35
  end
36
36
  end
@@ -1,5 +1,5 @@
1
1
  # Encapsulate the distance methods of the interval
2
- class HeadMusic::DiatonicInterval::Size
2
+ class HeadMusic::Analysis::DiatonicInterval::Size
3
3
  attr_reader :low_pitch, :high_pitch
4
4
 
5
5
  def initialize(pitch1, pitch2)
@@ -1,5 +1,8 @@
1
+ # A module for musical analysis
2
+ module HeadMusic::Analysis; end
3
+
1
4
  # A diatonic interval is the distance between two spelled pitches.
2
- class HeadMusic::DiatonicInterval
5
+ class HeadMusic::Analysis::DiatonicInterval
3
6
  include Comparable
4
7
 
5
8
  # TODO: include Named module
@@ -59,33 +62,33 @@ class HeadMusic::DiatonicInterval
59
62
  def self.get(identifier)
60
63
  name = Parser.new(identifier)
61
64
  semitones = Semitones.new(name.degree_name.to_sym, name.quality_name).count
62
- higher_pitch = HeadMusic::Pitch.from_number_and_letter(HeadMusic::Pitch.middle_c + semitones, name.higher_letter)
63
- new(HeadMusic::Pitch.middle_c, higher_pitch)
65
+ higher_pitch = HeadMusic::Rudiment::Pitch.from_number_and_letter(HeadMusic::Rudiment::Pitch.middle_c + semitones, name.higher_letter)
66
+ new(HeadMusic::Rudiment::Pitch.middle_c, higher_pitch)
64
67
  end
65
68
 
66
69
  def initialize(pitch1, pitch2)
67
- pitch1 = HeadMusic::Pitch.get(pitch1)
68
- pitch2 = HeadMusic::Pitch.get(pitch2)
70
+ pitch1 = HeadMusic::Rudiment::Pitch.get(pitch1)
71
+ pitch2 = HeadMusic::Rudiment::Pitch.get(pitch2)
69
72
  @lower_pitch, @higher_pitch = [pitch1, pitch2].sort
70
73
  end
71
74
 
72
75
  def quality
73
- HeadMusic::Quality.get(quality_name)
76
+ HeadMusic::Rudiment::Quality.get(quality_name)
74
77
  end
75
78
 
76
79
  def inversion
77
80
  inverted_low_pitch = lower_pitch
78
81
  while inverted_low_pitch < higher_pitch
79
- inverted_low_pitch = HeadMusic::Pitch.fetch_or_create(lower_pitch.spelling, inverted_low_pitch.register + 1)
82
+ inverted_low_pitch = HeadMusic::Rudiment::Pitch.fetch_or_create(lower_pitch.spelling, inverted_low_pitch.register + 1)
80
83
  end
81
- HeadMusic::DiatonicInterval.new(higher_pitch, inverted_low_pitch)
84
+ HeadMusic::Analysis::DiatonicInterval.new(higher_pitch, inverted_low_pitch)
82
85
  end
83
86
  alias_method :invert, :inversion
84
87
 
85
88
  def consonance(style = :standard_practice)
86
89
  consonance_for_perfect(style) ||
87
90
  consonance_for_major_and_minor ||
88
- HeadMusic::Consonance.get(:dissonant)
91
+ HeadMusic::Rudiment::Consonance.get(:dissonant)
89
92
  end
90
93
 
91
94
  def consonance?(style = :standard_practice)
@@ -106,13 +109,13 @@ class HeadMusic::DiatonicInterval
106
109
  end
107
110
 
108
111
  def above(pitch)
109
- pitch = HeadMusic::Pitch.get(pitch)
110
- HeadMusic::Pitch.from_number_and_letter(pitch + semitones, pitch.letter_name.steps_up(number - 1))
112
+ pitch = HeadMusic::Rudiment::Pitch.get(pitch)
113
+ HeadMusic::Rudiment::Pitch.from_number_and_letter(pitch + semitones, pitch.letter_name.steps_up(number - 1))
111
114
  end
112
115
 
113
116
  def below(pitch)
114
- pitch = HeadMusic::Pitch.get(pitch)
115
- HeadMusic::Pitch.from_number_and_letter(pitch - semitones, pitch.letter_name.steps_down(number - 1))
117
+ pitch = HeadMusic::Rudiment::Pitch.get(pitch)
118
+ HeadMusic::Rudiment::Pitch.from_number_and_letter(pitch - semitones, pitch.letter_name.steps_down(number - 1))
116
119
  end
117
120
 
118
121
  def interval_class
@@ -128,7 +131,7 @@ class HeadMusic::DiatonicInterval
128
131
  alias_method :diatonic_generic_interval, :simple_steps
129
132
 
130
133
  def <=>(other)
131
- other = self.class.get(other) unless other.is_a?(HeadMusic::DiatonicInterval)
134
+ other = self.class.get(other) unless other.is_a?(HeadMusic::Analysis::DiatonicInterval)
132
135
  semitones <=> other.semitones
133
136
  end
134
137
 
@@ -155,11 +158,11 @@ class HeadMusic::DiatonicInterval
155
158
  end
156
159
 
157
160
  def consonance_for_perfect(style = :standard_practice)
158
- HeadMusic::Consonance.get(dissonant_fourth?(style) ? :dissonant : :perfect) if perfect?
161
+ HeadMusic::Rudiment::Consonance.get(dissonant_fourth?(style) ? :dissonant : :perfect) if perfect?
159
162
  end
160
163
 
161
164
  def consonance_for_major_and_minor
162
- HeadMusic::Consonance.get((third_or_compound? || sixth_or_compound?) ? :imperfect : :dissonant) if major? || minor?
165
+ HeadMusic::Rudiment::Consonance.get((third_or_compound? || sixth_or_compound?) ? :imperfect : :dissonant) if major? || minor?
163
166
  end
164
167
 
165
168
  def dissonant_fourth?(style = :standard_practice)
@@ -1,5 +1,8 @@
1
+ # A module for musical analysis
2
+ module HeadMusic::Analysis; end
3
+
1
4
  # A harmonic interval is the diatonic interval between two notes sounding together.
2
- class HeadMusic::HarmonicInterval
5
+ class HeadMusic::Analysis::HarmonicInterval
3
6
  attr_reader :voice1, :voice2, :position
4
7
 
5
8
  def initialize(voice1, voice2, position)
@@ -9,7 +12,7 @@ class HeadMusic::HarmonicInterval
9
12
  end
10
13
 
11
14
  def diatonic_interval
12
- @diatonic_interval ||= HeadMusic::DiatonicInterval.new(lower_pitch, upper_pitch)
15
+ @diatonic_interval ||= HeadMusic::Analysis::DiatonicInterval.new(lower_pitch, upper_pitch)
13
16
  end
14
17
 
15
18
  def voices
@@ -1,20 +1,23 @@
1
+ # A module for musical analysis
2
+ module HeadMusic::Analysis; end
3
+
1
4
  # An Interval Cycle is a collection of pitch classes created from a sequence of the same interval class.
2
- class HeadMusic::IntervalCycle
5
+ class HeadMusic::Analysis::IntervalCycle
3
6
  attr_reader :interval, :starting_pitch
4
7
 
5
8
  def self.get(interval = 7)
6
9
  @interval_cycles ||= {}
7
10
  interval = interval.to_s.gsub(/^C/i, "").to_i
8
- interval = HeadMusic::ChromaticInterval.get(interval)
11
+ interval = HeadMusic::Rudiment::ChromaticInterval.get(interval)
9
12
  @interval_cycles[interval.to_i] ||= new(interval: interval, starting_pitch: "C4")
10
13
  end
11
14
 
12
15
  def initialize(interval:, starting_pitch: "C4")
13
- @interval = interval if interval.is_a?(HeadMusic::DiatonicInterval)
14
- @interval ||= interval if interval.is_a?(HeadMusic::ChromaticInterval)
15
- @interval ||= HeadMusic::ChromaticInterval.get(interval) if interval.to_s.match?(/\d/)
16
- @interval ||= HeadMusic::DiatonicInterval.get(interval)
17
- @starting_pitch = HeadMusic::Pitch.get(starting_pitch)
16
+ @interval = interval if interval.is_a?(HeadMusic::Analysis::DiatonicInterval)
17
+ @interval ||= interval if interval.is_a?(HeadMusic::Rudiment::ChromaticInterval)
18
+ @interval ||= HeadMusic::Rudiment::ChromaticInterval.get(interval) if interval.to_s.match?(/\d/)
19
+ @interval ||= HeadMusic::Analysis::DiatonicInterval.get(interval)
20
+ @starting_pitch = HeadMusic::Rudiment::Pitch.get(starting_pitch)
18
21
  end
19
22
 
20
23
  def pitches
@@ -26,7 +29,7 @@ class HeadMusic::IntervalCycle
26
29
  end
27
30
 
28
31
  def pitch_class_set
29
- @pitch_class_set ||= HeadMusic::PitchClassSet.new(pitches)
32
+ @pitch_class_set ||= HeadMusic::Analysis::PitchClassSet.new(pitches)
30
33
  end
31
34
 
32
35
  def spellings
@@ -48,6 +51,6 @@ class HeadMusic::IntervalCycle
48
51
  end
49
52
 
50
53
  def octave
51
- @octave ||= HeadMusic::DiatonicInterval.get(:perfect_octave)
54
+ @octave ||= HeadMusic::Analysis::DiatonicInterval.get(:perfect_octave)
52
55
  end
53
56
  end
@@ -1,5 +1,8 @@
1
+ # A module for musical analysis
2
+ module HeadMusic::Analysis; end
3
+
1
4
  # A melodic interval is the distance between one note and the next.
2
- class HeadMusic::MelodicInterval
5
+ class HeadMusic::Analysis::MelodicInterval
3
6
  attr_reader :first_note, :second_note
4
7
 
5
8
  def initialize(note1, note2)
@@ -8,7 +11,7 @@ class HeadMusic::MelodicInterval
8
11
  end
9
12
 
10
13
  def diatonic_interval
11
- @diatonic_interval ||= HeadMusic::DiatonicInterval.new(first_pitch, second_pitch)
14
+ @diatonic_interval ||= HeadMusic::Analysis::DiatonicInterval.new(first_pitch, second_pitch)
12
15
  end
13
16
 
14
17
  def position_start
@@ -56,7 +59,7 @@ class HeadMusic::MelodicInterval
56
59
  end
57
60
 
58
61
  def spans?(pitch)
59
- pitch >= low_pitch && pitch <= high_pitch
62
+ pitch.between?(low_pitch, high_pitch)
60
63
  end
61
64
 
62
65
  def high_pitch
@@ -84,7 +87,7 @@ class HeadMusic::MelodicInterval
84
87
  combined_pitches = (pitches + other_interval.pitches).uniq
85
88
  return false if combined_pitches.length < 3
86
89
 
87
- HeadMusic::PitchSet.new(combined_pitches).consonant_triad?
90
+ HeadMusic::Analysis::PitchSet.new(combined_pitches).consonant_triad?
88
91
  end
89
92
 
90
93
  def method_missing(method_name, *args, &block)
@@ -1,5 +1,8 @@
1
+ # A module for musical analysis
2
+ module HeadMusic::Analysis; end
3
+
1
4
  # Motion defines the relative pitch direction of the upper and lower voices of subsequence intervals.
2
- class HeadMusic::Motion
5
+ class HeadMusic::Analysis::Motion
3
6
  attr_reader :first_harmonic_interval, :second_harmonic_interval
4
7
 
5
8
  def initialize(first_harmonic_interval, second_harmonic_interval)
@@ -56,11 +59,11 @@ class HeadMusic::Motion
56
59
  private
57
60
 
58
61
  def upper_melodic_interval
59
- HeadMusic::MelodicInterval.new(upper_notes.first, upper_notes.last)
62
+ HeadMusic::Analysis::MelodicInterval.new(upper_notes.first, upper_notes.last)
60
63
  end
61
64
 
62
65
  def lower_melodic_interval
63
- HeadMusic::MelodicInterval.new(lower_notes.first, lower_notes.last)
66
+ HeadMusic::Analysis::MelodicInterval.new(lower_notes.first, lower_notes.last)
64
67
  end
65
68
 
66
69
  def upper_notes
@@ -1,13 +1,16 @@
1
+ # A module for musical analysis
2
+ module HeadMusic::Analysis; end
3
+
1
4
  # A PitchClassSet represents a pitch-class set or pitch collection.
2
5
  # See also: PitchSet, PitchClass
3
- class HeadMusic::PitchClassSet
6
+ class HeadMusic::Analysis::PitchClassSet
4
7
  attr_reader :pitch_classes
5
8
 
6
9
  delegate :empty?, to: :pitch_classes
7
10
  alias_method :empty_set?, :empty?
8
11
 
9
12
  def initialize(identifiers)
10
- @pitch_classes = identifiers.map { |identifier| HeadMusic::PitchClass.get(identifier) }.uniq.sort
13
+ @pitch_classes = identifiers.map { |identifier| HeadMusic::Rudiment::PitchClass.get(identifier) }.uniq.sort
11
14
  end
12
15
 
13
16
  def to_s
@@ -1,6 +1,9 @@
1
+ # A module for musical analysis
2
+ module HeadMusic::Analysis; end
3
+
1
4
  # A PitchSet is a collection of one or more pitches.
2
5
  # See also: PitchClassSet
3
- class HeadMusic::PitchSet
6
+ class HeadMusic::Analysis::PitchSet
4
7
  TERTIAN_SONORITIES = {
5
8
  implied_triad: [3],
6
9
  triad: [3, 5],
@@ -20,7 +23,7 @@ class HeadMusic::PitchSet
20
23
  delegate :size, to: :pitch_class_set, prefix: true
21
24
 
22
25
  def initialize(pitches)
23
- @pitches = pitches.map { |pitch| HeadMusic::Pitch.get(pitch) }.sort.uniq
26
+ @pitches = pitches.map { |pitch| HeadMusic::Rudiment::Pitch.get(pitch) }.sort.uniq
24
27
  end
25
28
 
26
29
  def pitch_classes
@@ -28,22 +31,22 @@ class HeadMusic::PitchSet
28
31
  end
29
32
 
30
33
  def pitch_class_set
31
- @pitch_class_set ||= HeadMusic::PitchClassSet.new(pitch_classes)
34
+ @pitch_class_set ||= HeadMusic::Analysis::PitchClassSet.new(pitch_classes)
32
35
  end
33
36
 
34
37
  def reduction
35
- @reduction ||= HeadMusic::PitchSet.new(reduction_pitches)
38
+ @reduction ||= HeadMusic::Analysis::PitchSet.new(reduction_pitches)
36
39
  end
37
40
 
38
41
  def diatonic_intervals
39
42
  @diatonic_intervals ||= pitches.each_cons(2).map do |pitch_pair|
40
- HeadMusic::DiatonicInterval.new(*pitch_pair)
43
+ HeadMusic::Analysis::DiatonicInterval.new(*pitch_pair)
41
44
  end
42
45
  end
43
46
 
44
47
  def diatonic_intervals_above_bass_pitch
45
48
  @diatonic_intervals_above_bass_pitch ||= pitches_above_bass_pitch.map do |pitch|
46
- HeadMusic::DiatonicInterval.new(bass_pitch, pitch)
49
+ HeadMusic::Analysis::DiatonicInterval.new(bass_pitch, pitch)
47
50
  end
48
51
  end
49
52
 
@@ -62,15 +65,15 @@ class HeadMusic::PitchSet
62
65
  end
63
66
 
64
67
  def invert
65
- inverted_pitch = pitches[0] + HeadMusic::DiatonicInterval.get("perfect octave")
68
+ inverted_pitch = pitches[0] + HeadMusic::Analysis::DiatonicInterval.get("perfect octave")
66
69
  new_pitches = pitches.drop(1) + [inverted_pitch]
67
- HeadMusic::PitchSet.new(new_pitches)
70
+ HeadMusic::Analysis::PitchSet.new(new_pitches)
68
71
  end
69
72
 
70
73
  def uninvert
71
- inverted_pitch = pitches[-1] - HeadMusic::DiatonicInterval.get("perfect octave")
74
+ inverted_pitch = pitches[-1] - HeadMusic::Analysis::DiatonicInterval.get("perfect octave")
72
75
  new_pitches = [inverted_pitch] + pitches[0..-2]
73
- HeadMusic::PitchSet.new(new_pitches)
76
+ HeadMusic::Analysis::PitchSet.new(new_pitches)
74
77
  end
75
78
 
76
79
  def bass_pitch
@@ -188,7 +191,7 @@ class HeadMusic::PitchSet
188
191
 
189
192
  def reduction_pitches
190
193
  pitches.map do |pitch|
191
- pitch = HeadMusic::Pitch.fetch_or_create(pitch.spelling, pitch.register - 1) while pitch > bass_pitch + 12
194
+ pitch = HeadMusic::Rudiment::Pitch.fetch_or_create(pitch.spelling, pitch.register - 1) while pitch > bass_pitch + 12
192
195
  pitch
193
196
  end.sort
194
197
  end
@@ -1,7 +1,10 @@
1
+ # A module for musical analysis
2
+ module HeadMusic::Analysis; end
3
+
1
4
  # A Sonority describes a set of pitch class intervalic relationships.
2
5
  # For example, a minor triad, or a major-minor seventh chord.
3
6
  # The Sonority class is a factory for returning one of its subclasses.
4
- class HeadMusic::Sonority
7
+ class HeadMusic::Analysis::Sonority
5
8
  SONORITIES = {
6
9
  major_triad: %w[M3 P5],
7
10
  minor_triad: %w[m3 P5],
@@ -110,12 +113,12 @@ class HeadMusic::Sonority
110
113
  return nil unless identifier
111
114
 
112
115
  @diatonic_intervals_above_bass_pitch ||=
113
- SONORITIES[identifier].map { |shorthand| HeadMusic::DiatonicInterval.get(shorthand) }
116
+ SONORITIES[identifier].map { |shorthand| HeadMusic::Analysis::DiatonicInterval.get(shorthand) }
114
117
  end
115
118
 
116
119
  def ==(other)
117
- other = HeadMusic::PitchSet.new(other) if other.is_a?(Array)
118
- other = self.class.new(other) if other.is_a?(HeadMusic::PitchSet)
120
+ other = HeadMusic::Analysis::PitchSet.new(other) if other.is_a?(Array)
121
+ other = self.class.new(other) if other.is_a?(HeadMusic::Analysis::PitchSet)
119
122
  identifier == other.identifier
120
123
  end
121
124
  end
@@ -9,8 +9,8 @@ class HeadMusic::Content::Bar
9
9
 
10
10
  def initialize(composition, key_signature: nil, meter: nil)
11
11
  @composition = composition
12
- @key_signature = HeadMusic::KeySignature.get(key_signature) if key_signature
13
- @meter = HeadMusic::Meter.get(meter) if meter
12
+ @key_signature = HeadMusic::Rudiment::KeySignature.get(key_signature) if key_signature
13
+ @meter = HeadMusic::Rudiment::Meter.get(meter) if meter
14
14
  end
15
15
 
16
16
  def to_s
@@ -65,9 +65,9 @@ class HeadMusic::Content::Composition
65
65
 
66
66
  def ensure_attributes(name, key_signature, meter)
67
67
  @name = name || "Composition"
68
- @key_signature = HeadMusic::KeySignature.get(key_signature) if key_signature
69
- @key_signature ||= HeadMusic::KeySignature.default
70
- @meter = meter ? HeadMusic::Meter.get(meter) : HeadMusic::Meter.default
68
+ @key_signature = HeadMusic::Rudiment::KeySignature.get(key_signature) if key_signature
69
+ @key_signature ||= HeadMusic::Rudiment::KeySignature.default
70
+ @meter = meter ? HeadMusic::Rudiment::Meter.get(meter) : HeadMusic::Rudiment::Meter.default
71
71
  end
72
72
 
73
73
  def last_meter_change(bar_number)
@@ -10,7 +10,7 @@ class HeadMusic::Content::Note
10
10
  attr_accessor :pitch, :rhythmic_value, :voice, :position
11
11
 
12
12
  def initialize(pitch, rhythmic_value, voice = nil, position = nil)
13
- @pitch = HeadMusic::Pitch.get(pitch)
13
+ @pitch = HeadMusic::Rudiment::Pitch.get(pitch)
14
14
  @rhythmic_value = HeadMusic::Content::RhythmicValue.get(rhythmic_value)
15
15
  @voice = voice || HeadMusic::Content::Voice.new
16
16
  @position = position || HeadMusic::Content::Position.new(@voice.composition, "1:1")
@@ -56,7 +56,7 @@ class HeadMusic::Content::Placement
56
56
  @voice = voice
57
57
  ensure_position(position)
58
58
  @rhythmic_value = HeadMusic::Content::RhythmicValue.get(rhythmic_value)
59
- @pitch = HeadMusic::Pitch.get(pitch)
59
+ @pitch = HeadMusic::Rudiment::Pitch.get(pitch)
60
60
  end
61
61
 
62
62
  def ensure_position(position)
@@ -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::RhythmicUnit, Symbol, String].include?(other.class)
56
+ other = HeadMusic::Content::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
 
@@ -12,7 +12,7 @@ class HeadMusic::Content::RhythmicValue
12
12
  case identifier
13
13
  when HeadMusic::Content::RhythmicValue
14
14
  identifier
15
- when HeadMusic::RhythmicUnit
15
+ when HeadMusic::Rudiment::RhythmicUnit
16
16
  new(identifier)
17
17
  when Symbol, String
18
18
  identifier = identifier.to_s.downcase.strip.gsub(/\W+/, "_")
@@ -43,7 +43,7 @@ class HeadMusic::Content::RhythmicValue
43
43
  end
44
44
 
45
45
  def initialize(unit, dots: nil, tied_value: nil)
46
- @unit = HeadMusic::RhythmicUnit.get(unit)
46
+ @unit = HeadMusic::Rudiment::RhythmicUnit.get(unit)
47
47
  @dots = [0, 1, 2, 3].include?(dots) ? dots : 0
48
48
  @tied_value = tied_value
49
49
  end
@@ -65,7 +65,7 @@ class HeadMusic::Content::RhythmicValue
65
65
  end
66
66
 
67
67
  def ticks
68
- HeadMusic::Rhythm::PPQN * 4 * total_value
68
+ HeadMusic::Rudiment::Rhythm::PPQN * 4 * total_value
69
69
  end
70
70
 
71
71
  def per_whole
@@ -1,13 +1,16 @@
1
+ # A module for musical content
2
+ module HeadMusic::Content; end
3
+
1
4
  # A staff is a set of lines and spaces that provides context for a pitch
2
- class HeadMusic::Staff
5
+ class HeadMusic::Content::Staff
3
6
  DEFAULT_LINE_COUNT = 5
4
7
 
5
8
  attr_reader :default_clef, :line_count, :instrument
6
9
 
7
10
  def initialize(default_clef_key, instrument: nil, line_count: nil)
8
- @default_clef = HeadMusic::Clef.get(default_clef_key)
11
+ @default_clef = HeadMusic::Rudiment::Clef.get(default_clef_key)
9
12
  @line_count = line_count || DEFAULT_LINE_COUNT
10
- @instrument = HeadMusic::Instrument.get(instrument) if instrument
13
+ @instrument = HeadMusic::Instruments::Instrument.get(instrument) if instrument
11
14
  end
12
15
 
13
16
  def clef
@@ -56,12 +56,12 @@ class HeadMusic::Content::Voice
56
56
  end
57
57
 
58
58
  def range
59
- HeadMusic::DiatonicInterval.new(lowest_pitch, highest_pitch)
59
+ HeadMusic::Analysis::DiatonicInterval.new(lowest_pitch, highest_pitch)
60
60
  end
61
61
 
62
62
  def melodic_intervals
63
63
  @melodic_intervals ||=
64
- notes.each_cons(2).map { |note_pair| HeadMusic::MelodicInterval.new(*note_pair) }
64
+ notes.each_cons(2).map { |note_pair| HeadMusic::Analysis::MelodicInterval.new(*note_pair) }
65
65
  end
66
66
 
67
67
  def leaps