head_music 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 63d427018297be00f798c809a49236ad36556096
4
- data.tar.gz: 8fcbff20bc04bee42a900b5d9bef1dabb9b9bf1f
3
+ metadata.gz: 27bbe45d50118d4f5f4bcf02e3192da3ddd2ec70
4
+ data.tar.gz: 1900eb67572a4bfb79e0b91c05673bfadd1f7c2c
5
5
  SHA512:
6
- metadata.gz: 5eec89666c474d7cbe5114ca4504f57bdddfc3eb9899b1fe666946cb9b4c8fd8dc4ac144a95512bb9dd0f86a7060fd6e1a201fd78daa94f701095bf8456ecdca
7
- data.tar.gz: 692a3fc51fdbe388e498d873a45d4f50776dcf9b5669b65bf4694986aa94b8be8a7b4208a6243487c21ba00dbab86f4be82aeeb45470c358f1fed40d730e1f62
6
+ metadata.gz: 30f5b988d501ca3286bc41da70c3ca3672d9d30438d81a5740c1c8db4bd1d4e3e9af594302aa928afea446c2d6197f1b3aa0d69280c1e94fc986e03359712872
7
+ data.tar.gz: d5534e5c7dadf6b7339d29b4db89256cf2d853b5415add44032c15eb24f1e10a83bb0d185d4437ef319a29f7c003f0b90228e3cce19bcfe22d5d73646255f561
@@ -2,18 +2,63 @@ class HeadMusic::FunctionalInterval
2
2
  NUMBER_NAMES = %w[unison second third fourth fifth sixth seventh octave ninth tenth eleventh twelfth thirteenth fourteenth fifteenth sixteenth seventeenth]
3
3
  NAME_SUFFIXES = Hash.new('th').merge({ 1 => 'st', 2 => 'nd', 3 => 'rd' })
4
4
 
5
- QUALITY = {
6
- unison: {perfect: 0},
7
- second: {major: 2},
8
- third: {major: 4},
9
- fourth: {perfect: 5},
10
- fifth: {perfect: 7},
11
- sixth: {major: 9},
12
- seventh: {major: 11},
5
+ QUALITY_SEMITONES = {
6
+ unison: { perfect: 0 },
7
+ second: { major: 2 },
8
+ third: { major: 4 },
9
+ fourth: { perfect: 5 },
10
+ fifth: { perfect: 7 },
11
+ sixth: { major: 9 },
12
+ seventh: { major: 11 },
13
+ octave: { perfect: 12 },
14
+ ninth: { major: 14 },
15
+ tenth: { major: 16 },
16
+ eleventh: { perfect: 17 },
17
+ twelfth: { perfect: 19 },
18
+ thirteenth: { major: 21 },
19
+ fourteenth: { major: 23 },
20
+ fifteenth: { perfect: 24 },
21
+ sixteenth: { major: 26 },
22
+ seventeenth: { major: 28 }
13
23
  }
14
24
 
15
25
  attr_reader :lower_pitch, :higher_pitch
16
26
 
27
+ delegate :to_s, to: :name
28
+ delegate :==, to: :to_s
29
+
30
+ def self.get(name)
31
+ words = name.to_s.split(/[_ ]+/)
32
+ quality_name, degree_name = words[0..-2].join(' '), words.last
33
+ lower_pitch = HeadMusic::Pitch.get('C4')
34
+ steps = NUMBER_NAMES.index(degree_name)
35
+ higher_letter = lower_pitch.letter.steps(steps)
36
+ semitones = degree_quality_semitones.dig(degree_name.to_sym, quality_name.to_sym)
37
+ higher_pitch = HeadMusic::Pitch.from_number_and_letter(lower_pitch + semitones, higher_letter)
38
+ new(lower_pitch, higher_pitch)
39
+ end
40
+
41
+ def self.degree_quality_semitones
42
+ @degree_quality_semitones ||= begin
43
+ degree_quality_semitones = QUALITY_SEMITONES
44
+ QUALITY_SEMITONES.each do |degree_name, qualities|
45
+ default_quality = qualities.keys.first
46
+ if default_quality == :perfect
47
+ modification_hash = HeadMusic::Quality::PERFECT_INTERVAL_MODIFICATION.invert
48
+ else
49
+ modification_hash = HeadMusic::Quality::MAJOR_INTERVAL_MODIFICATION.invert
50
+ end
51
+ default_semitones = qualities[default_quality]
52
+ modification_hash.each do |quality_name, delta|
53
+ if quality_name != default_quality
54
+ degree_quality_semitones[degree_name][quality_name] = default_semitones + delta
55
+ end
56
+ end
57
+ end
58
+ degree_quality_semitones
59
+ end
60
+ end
61
+
17
62
  def initialize(pitch1, pitch2)
18
63
  @lower_pitch, @higher_pitch = [HeadMusic::Pitch.get(pitch1), HeadMusic::Pitch.get(pitch2)].sort
19
64
  end
@@ -69,13 +114,9 @@ class HeadMusic::FunctionalInterval
69
114
  end
70
115
 
71
116
  def quality_name
72
- starting_quality = QUALITY[simple_number_name.to_sym].keys.first
73
- delta = simple_semitones - QUALITY[simple_number_name.to_sym][starting_quality]
74
- if starting_quality == :perfect
75
- HeadMusic::Quality::PERFECT_INTERVAL_MODIFICATION[delta]
76
- elsif starting_quality == :major
77
- HeadMusic::Quality::MAJOR_INTERVAL_MODIFICATION[delta]
78
- end
117
+ starting_quality = QUALITY_SEMITONES[simple_number_name.to_sym].keys.first
118
+ delta = simple_semitones - QUALITY_SEMITONES[simple_number_name.to_sym][starting_quality]
119
+ HeadMusic::Quality::from(starting_quality, delta)
79
120
  end
80
121
 
81
122
  def simple_number_name
@@ -87,4 +128,12 @@ class HeadMusic::FunctionalInterval
87
128
  number.to_s + NAME_SUFFIXES[number % 10]
88
129
  end
89
130
  end
131
+
132
+ def inversion
133
+ inverted_low_pitch = lower_pitch
134
+ while inverted_low_pitch < higher_pitch
135
+ inverted_low_pitch += 12
136
+ end
137
+ HeadMusic::FunctionalInterval.new(higher_pitch, inverted_low_pitch)
138
+ end
90
139
  end
@@ -58,6 +58,10 @@ class HeadMusic::Letter
58
58
  NAMES.index(self.to_s) + 1
59
59
  end
60
60
 
61
+ def steps(num)
62
+ cycle[num]
63
+ end
64
+
61
65
  def steps_to(other, direction = :ascending)
62
66
  other = Letter.get(other)
63
67
  other_position = other.position
@@ -7,6 +7,7 @@ class HeadMusic::Pitch
7
7
  delegate :letter, :letter_cycle, to: :spelling
8
8
  delegate :accidental, :sharp?, :flat?, to: :spelling
9
9
  delegate :pitch_class, to: :spelling
10
+ delegate :semitones, to: :accidental, prefix: true, allow_nil: true
10
11
 
11
12
  delegate :smallest_interval_to, to: :pitch_class
12
13
 
@@ -29,7 +30,7 @@ class HeadMusic::Pitch
29
30
  def self.from_number_and_letter(number, letter)
30
31
  letter = HeadMusic::Letter.get(letter)
31
32
  natural_letter_pitch = get(HeadMusic::Letter.get(letter).pitch_class)
32
- natural_letter_pitch += 12 while (number - natural_letter_pitch.to_i) >= 11
33
+ natural_letter_pitch += 12 while (number - natural_letter_pitch.to_i).to_i >= 11
33
34
  natural_letter_pitch = get(natural_letter_pitch)
34
35
  accidental_interval = natural_letter_pitch.smallest_interval_to(HeadMusic::PitchClass.get(number))
35
36
  accidental = HeadMusic::Accidental.for_interval(accidental_interval)
@@ -55,7 +56,7 @@ class HeadMusic::Pitch
55
56
  end
56
57
 
57
58
  def midi_note_number
58
- (octave + 1) * 12 + pitch_class.to_i
59
+ (octave + 1) * 12 + letter.pitch_class.to_i + accidental_semitones.to_i
59
60
  end
60
61
 
61
62
  alias_method :midi, :midi_note_number
@@ -32,6 +32,14 @@ class HeadMusic::Quality
32
32
  @qualities[identifier] ||= new(identifier) if NAMES.include?(identifier)
33
33
  end
34
34
 
35
+ def self.from(starting_quality, delta)
36
+ if starting_quality == :perfect
37
+ PERFECT_INTERVAL_MODIFICATION[delta].to_s.gsub(/_+/, ' ')
38
+ elsif starting_quality == :major
39
+ MAJOR_INTERVAL_MODIFICATION[delta].to_s.gsub(/_+/, ' ')
40
+ end
41
+ end
42
+
35
43
  attr_reader :name
36
44
  delegate :to_s, to: :name
37
45
 
@@ -1,3 +1,3 @@
1
1
  module HeadMusic
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: head_music
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rob Head
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-20 00:00:00.000000000 Z
11
+ date: 2017-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport