head_music 0.3.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 67e0581fd0dc08759395cc97286a1e96b538147d
4
- data.tar.gz: dc985557ff8d0e1aa4720a4732a8b29a643251d8
3
+ metadata.gz: 607c84eac4fe859f29c47a023d57f923b7d3d9dc
4
+ data.tar.gz: 6f2c73ba4b7ecfd7c5897668a270070f1082d3a5
5
5
  SHA512:
6
- metadata.gz: 09fcb0a4675636f67580e095b73e5640d122d7ad72df17b0677456f0234778df1a43137eb1d3c7c5e2852a0f8acada492a179bb0e8da3e6b64252164cc554fe2
7
- data.tar.gz: b1b1809ed935b1a03688220039cdce9ecd8c98a55d31d71a818077ce2b2a4e416d8a00ae6dbbba7fe742cf0dc4f507ce173b4a395d4638b4d0adef497f64fb18
6
+ metadata.gz: acb22d69a21f890b57e08e8a4a113ef491388222a33f3e0bf3ec1750673f2caaddd6928c5047023ef1d5bbe3a71f2f665adc23b2e934f4c0e252f7fad269d7c1
7
+ data.tar.gz: aeb7849fe4c6eb607804ebf6d3155c67f04dd477dcc412612dea0fd5929631859ea4f38992423599137659b338c3b3c6e6feb8a9bf40c5388b0d0b60bb0c7102
@@ -54,5 +54,13 @@ class HeadMusic::Letter
54
54
  to_s == value.to_s
55
55
  end
56
56
 
57
+ def cycle
58
+ cycle = NAMES
59
+ while cycle.first != self.to_s
60
+ cycle = cycle.rotate
61
+ end
62
+ cycle
63
+ end
64
+
57
65
  private_class_method :new
58
66
  end
@@ -4,7 +4,7 @@ class HeadMusic::Pitch
4
4
  attr_reader :spelling
5
5
  attr_reader :octave
6
6
 
7
- delegate :letter, to: :spelling
7
+ delegate :letter, :letter_cycle, to: :spelling
8
8
  delegate :accidental, :sharp?, :flat?, to: :spelling
9
9
  delegate :pitch_class, to: :spelling
10
10
 
@@ -88,5 +88,9 @@ class HeadMusic::Pitch
88
88
  self.midi_note_number <=> other.midi_note_number
89
89
  end
90
90
 
91
+ def scale(scale_type_name = nil)
92
+ HeadMusic::Scale.get(self, scale_type_name)
93
+ end
94
+
91
95
  private_class_method :new
92
96
  end
@@ -17,31 +17,14 @@ class HeadMusic::Scale
17
17
 
18
18
  def pitches
19
19
  @pitches ||= begin
20
- pitches = [root_pitch]
21
- letters_cycle = HeadMusic::Letter::NAMES
22
- letters_cycle = letters_cycle.rotate while letters_cycle.first != root_pitch.letter.to_s
20
+ letter_cycle = root_pitch.letter_cycle
23
21
  semitones_from_root = 0
24
- if scale_type.parent
25
- parent_scale_pitches = HeadMusic::Scale.get(root_pitch, scale_type.parent_name).pitches
26
- end
27
- scale_type.intervals.each_with_index do |semitones, i|
28
- semitones_from_root += semitones
29
- pitch_number = root_pitch.pitch_class.to_i + semitones_from_root
30
- if scale_type.intervals.length == 7
31
- current_letter = letters_cycle[(i + 1) % 7]
32
- elsif scale_type.intervals.length < 7 && scale_type.parent
33
- current_letter = parent_scale_pitches.detect { |parent_scale_pitches|
34
- parent_scale_pitches.pitch_class == (root_pitch + semitones_from_root).to_i % 12
35
- }.letter
36
- elsif root_pitch.flat?
37
- current_letter = HeadMusic::PitchClass::FLAT_SPELLINGS[pitch_number % 12]
38
- else
39
- current_letter = HeadMusic::PitchClass::SHARP_SPELLINGS[pitch_number % 12]
22
+ [root_pitch].tap do |pitches|
23
+ scale_type.intervals.each_with_index do |semitones, i|
24
+ semitones_from_root += semitones
25
+ pitches << pitch_for_step(i+1, semitones_from_root)
40
26
  end
41
- pitch = HeadMusic::Pitch.from_number_and_letter(pitch_number, current_letter)
42
- pitches << pitch
43
27
  end
44
- pitches
45
28
  end
46
29
  end
47
30
 
@@ -65,4 +48,43 @@ class HeadMusic::Scale
65
48
  end
66
49
  spellings
67
50
  end
51
+
52
+ def letter_cycle
53
+ @letter_cycle ||= root_pitch.letter_cycle
54
+ end
55
+
56
+ def root_pitch_class
57
+ @root_pitch_class ||= root_pitch.pitch_class
58
+ end
59
+
60
+ private
61
+
62
+ def parent_scale_pitches
63
+ HeadMusic::Scale.get(root_pitch, scale_type.parent_name).pitches if scale_type.parent
64
+ end
65
+
66
+ def parent_scale_pitch_for(semitones_from_root)
67
+ parent_scale_pitches.detect { |parent_scale_pitch|
68
+ parent_scale_pitch.pitch_class == (root_pitch + semitones_from_root).to_i % 12
69
+ }
70
+ end
71
+
72
+ def letter_for_step(step, semitones_from_root)
73
+ pitch_class_number = (root_pitch.pitch_class.to_i + semitones_from_root) % 12
74
+ if scale_type.intervals.length == 7
75
+ letter_cycle[step % 7]
76
+ elsif scale_type.intervals.length < 7 && parent_scale_pitches
77
+ parent_scale_pitch_for(semitones_from_root).letter
78
+ elsif root_pitch.flat?
79
+ HeadMusic::PitchClass::FLAT_SPELLINGS[pitch_class_number]
80
+ else
81
+ HeadMusic::PitchClass::SHARP_SPELLINGS[pitch_class_number]
82
+ end
83
+ end
84
+
85
+ def pitch_for_step(step, semitones_from_root)
86
+ pitch_number = root_pitch_class.to_i + semitones_from_root
87
+ letter = letter_for_step(step, semitones_from_root)
88
+ HeadMusic::Pitch.from_number_and_letter(pitch_number, letter)
89
+ end
68
90
  end
@@ -8,6 +8,8 @@ class HeadMusic::Spelling
8
8
  attr_reader :accidental
9
9
 
10
10
  delegate :number, to: :pitch_class, prefix: true
11
+ delegate :to_i, to: :pitch_class_number
12
+ delegate :cycle, to: :letter, prefix: true
11
13
 
12
14
  def self.get(identifier)
13
15
  from_name(identifier) || from_number(identifier)
@@ -75,5 +77,9 @@ class HeadMusic::Spelling
75
77
  to_s == value.to_s
76
78
  end
77
79
 
80
+ def scale(scale_type_name = nil)
81
+ HeadMusic::Scale.get(self, scale_type_name)
82
+ end
83
+
78
84
  private_class_method :new
79
85
  end
@@ -1,3 +1,3 @@
1
1
  module HeadMusic
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.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.3.0
4
+ version: 0.3.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-19 00:00:00.000000000 Z
11
+ date: 2017-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport