coltrane 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/.bundle/config +2 -0
  3. data/.rspec +2 -0
  4. data/CODE_OF_CONDUCT.md +74 -0
  5. data/Gemfile +17 -0
  6. data/Gemfile.lock +164 -0
  7. data/Guardfile +71 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +41 -0
  10. data/Rakefile +6 -0
  11. data/bin/_guard-core +17 -0
  12. data/bin/bundler +17 -0
  13. data/bin/coderay +17 -0
  14. data/bin/coltrane +11 -0
  15. data/bin/console +14 -0
  16. data/bin/erubis +17 -0
  17. data/bin/guard +17 -0
  18. data/bin/htmldiff +17 -0
  19. data/bin/kill-pry-rescue +17 -0
  20. data/bin/ldiff +17 -0
  21. data/bin/listen +17 -0
  22. data/bin/nokogiri +17 -0
  23. data/bin/pry +17 -0
  24. data/bin/rackup +17 -0
  25. data/bin/rails +17 -0
  26. data/bin/rake +17 -0
  27. data/bin/rdoc +17 -0
  28. data/bin/rescue +17 -0
  29. data/bin/ri +17 -0
  30. data/bin/rspec +17 -0
  31. data/bin/rubocop +17 -0
  32. data/bin/ruby-parse +17 -0
  33. data/bin/ruby-rewrite +17 -0
  34. data/bin/setup +8 -0
  35. data/bin/sprockets +17 -0
  36. data/bin/thor +17 -0
  37. data/bin/tilt +17 -0
  38. data/coltrane.gemspec +35 -0
  39. data/db/cache.sqlite3 +0 -0
  40. data/db/cache_test.sqlite3 +0 -0
  41. data/db/config.yml +11 -0
  42. data/db/schema.rb +30 -0
  43. data/lib/coltrane.rb +48 -0
  44. data/lib/coltrane/cadence.rb +4 -0
  45. data/lib/coltrane/chord.rb +81 -0
  46. data/lib/coltrane/chord_cache.rb +4 -0
  47. data/lib/coltrane/chord_quality.rb +48 -0
  48. data/lib/coltrane/classic_scales.rb +134 -0
  49. data/lib/coltrane/essential_guitar_chords.rb +82 -0
  50. data/lib/coltrane/fret_set.rb +0 -0
  51. data/lib/coltrane/guitar.rb +15 -0
  52. data/lib/coltrane/guitar_chord.rb +50 -0
  53. data/lib/coltrane/guitar_chord_finder.rb +98 -0
  54. data/lib/coltrane/guitar_note.rb +50 -0
  55. data/lib/coltrane/guitar_note_set.rb +61 -0
  56. data/lib/coltrane/guitar_representation.rb +96 -0
  57. data/lib/coltrane/guitar_string.rb +52 -0
  58. data/lib/coltrane/interval.rb +33 -0
  59. data/lib/coltrane/interval_sequence.rb +70 -0
  60. data/lib/coltrane/interval_set.rb +23 -0
  61. data/lib/coltrane/mode.rb +0 -0
  62. data/lib/coltrane/note.rb +98 -0
  63. data/lib/coltrane/note_set.rb +50 -0
  64. data/lib/coltrane/piano_representation.rb +58 -0
  65. data/lib/coltrane/pitch.rb +27 -0
  66. data/lib/coltrane/progression.rb +4 -0
  67. data/lib/coltrane/qualities.rb +115 -0
  68. data/lib/coltrane/scale.rb +139 -0
  69. data/lib/coltrane/scale_cache.rb +4 -0
  70. data/lib/coltrane/scale_chord.rb +4 -0
  71. data/lib/coltrane/version.rb +3 -0
  72. metadata +144 -0
@@ -0,0 +1,70 @@
1
+ module Coltrane
2
+ # It describes a sequence of intervals
3
+ class IntervalSequence
4
+ attr_reader :intervals
5
+
6
+ def initialize(arg)
7
+ arg = [arg] if arg.class != Array
8
+ @intervals = arg.reduce([]) do |memo, arg_item|
9
+ case arg_item
10
+ when Numeric then memo << Interval.new(arg_item)
11
+ when Interval then memo << arg_item
12
+ when NoteSet then memo + intervals_from_note_set(arg_item)
13
+ end
14
+ end
15
+ end
16
+
17
+ def intervals_from_note_set(note_set)
18
+ note_numbers = note_set.notes.collect(&:number)
19
+ root = note_numbers.shift
20
+ note_numbers.reduce([Interval.new(0)]) do |memo, number|
21
+ number += 12 if number < root
22
+ memo << Interval.new(number - root)
23
+ end
24
+ end
25
+
26
+ def reordered
27
+ IntervalSequence.new @intervals.sort_by!(&:number)
28
+ end
29
+
30
+ def all
31
+ intervals
32
+ end
33
+
34
+ def [](x)
35
+ intervals[x]
36
+ end
37
+
38
+ def shift(ammount)
39
+ IntervalSequence.new(intervals.map do |i|
40
+ (i.number + ammount) % 12
41
+ end)
42
+ end
43
+
44
+ def zero_it
45
+ self.shift(-intervals.first.number)
46
+ end
47
+
48
+ def next_inversion
49
+ IntervalSequence.new(intervals.rotate(+1))
50
+ end
51
+
52
+ def previous_inversion
53
+ IntervalSequence.new(intervals.rotate(-1))
54
+ end
55
+
56
+ def inversions
57
+ Array.new(intervals.length) do |index|
58
+ IntervalSequence.new(interval.rotate(index))
59
+ end
60
+ end
61
+
62
+ def numbers
63
+ intervals.collect(&:number)
64
+ end
65
+
66
+ def names
67
+ intervals.collect(&:name)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,23 @@
1
+
2
+ # class IntervalSet
3
+ # def initialize(*intervals)
4
+ # @intervals = intervals
5
+ # @number_of_frets = 24
6
+ # sum = @intervals.reduce(:+)
7
+ # sum < 12 && @intervals << 12 - sum
8
+ # end
9
+
10
+ # def to_s
11
+ # @intervals.to_s
12
+ # end
13
+
14
+ # def to_frets(offset = 0)
15
+ # frets = [-offset]
16
+ # i = 0
17
+ # while frets.last < @number_of_frets
18
+ # frets << frets.last + @intervals[i % @intervals.length]
19
+ # i += 1
20
+ # end
21
+ # frets
22
+ # end
23
+ # end
File without changes
@@ -0,0 +1,98 @@
1
+ module Coltrane
2
+ # It describes a musical note, independent of octave
3
+ class Note
4
+ attr_reader :name
5
+
6
+ NOTES = {
7
+ 'C' => 0,
8
+ 'C#' => 1,
9
+ 'Db' => 1,
10
+ 'D' => 2,
11
+ 'D#' => 3,
12
+ 'Eb' => 3,
13
+ 'E' => 4,
14
+ 'F' => 5,
15
+ 'F#' => 6,
16
+ 'Gb' => 6,
17
+ 'G' => 7,
18
+ 'G#' => 8,
19
+ 'Ab' => 8,
20
+ 'A' => 9,
21
+ 'A#' => 10,
22
+ 'Bb' => 10,
23
+ 'B' => 11
24
+ }.freeze
25
+
26
+ def self.all
27
+ NOTES.keys.map {|n| Note.new(n)}
28
+ end
29
+
30
+ def accident?
31
+ [1,3,6,8,10].include?(number)
32
+ end
33
+
34
+ def initialize(arg)
35
+ case arg
36
+ when String
37
+ raise "invalid note: #{arg}" unless valid_note?(arg)
38
+ @name = arg
39
+ when Numeric then @name = name_from_number(arg)
40
+ end
41
+ end
42
+
43
+ def +(n)
44
+ case n
45
+ when Numeric then Note.new(number + n)
46
+ when Note then Chord.new(number + n.number)
47
+ end
48
+ end
49
+
50
+ def -(n)
51
+ case n
52
+ when Numeric then Note.new(number + n)
53
+ when Note then Interval.new((number - n.number) % 12)
54
+ end
55
+ end
56
+
57
+ def valid_note?(note_name)
58
+ NOTES.key?(note_name)
59
+ end
60
+
61
+ def number
62
+ NOTES[name]
63
+ end
64
+
65
+ def interval_to(note_name)
66
+ Interval.new(Note.new(note_name).number - number)
67
+ end
68
+
69
+ def transpose_by(interval_number)
70
+ @name = name_from_number(number + interval_number)
71
+ self
72
+ end
73
+
74
+ def guitar_notes
75
+ Guitar.strings.reduce([]) do |memo, guitar_string|
76
+ memo + in_guitar_string(guitar_string)
77
+ end
78
+ end
79
+
80
+ def on_guitar
81
+ GuitarNoteSet.new(guitar_notes).render
82
+ end
83
+
84
+ def in_guitar_string(guitar_string)
85
+ guitar_string.guitar_notes_for_note(self)
86
+ end
87
+
88
+ def in_guitar_string_region(guitar_string, region)
89
+ guitar_string.guitar_notes_for_note_in_region(self, region)
90
+ end
91
+
92
+ protected
93
+
94
+ def name_from_number(number)
95
+ NOTES.key(number % 12)
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,50 @@
1
+ module Coltrane
2
+ # It describes a set of notes
3
+ class NoteSet
4
+ attr_reader :notes
5
+
6
+ def initialize(arg)
7
+ @notes = case arg
8
+ when String then notes_from_note_string(arg)
9
+ when Array then notes_from_note_array(arg)
10
+ end
11
+ end
12
+
13
+ def root_note
14
+ notes.sort_by(&:number).first
15
+ end
16
+
17
+ def transpose_to(note_name)
18
+ transpose_by(root_note.interval_to(note_name).number)
19
+ end
20
+
21
+ def transpose_by(interval)
22
+ notes.map do |note|
23
+ note.transpose_by(interval)
24
+ end
25
+ end
26
+
27
+ def guitar_notes
28
+ GuitarNoteSet.new(notes.map(&:guitar_notes).flatten)
29
+ end
30
+
31
+ def interval_sequence
32
+ IntervalSequence.new(self)
33
+ end
34
+
35
+ protected
36
+
37
+ def notes_from_note_string(note_string)
38
+ notes_from_note_array(note_string.split(' '))
39
+ end
40
+
41
+ def notes_from_note_array(note_array)
42
+ note_array.collect do |note|
43
+ case note
44
+ when String then Note.new(note)
45
+ when Note then note
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,58 @@
1
+ module Coltrane
2
+ class PianoRepresentation
3
+ PIANO_TEMPLATE = <<~ASCII
4
+ ┌─┬─┬┬─┬─╥─┬─┬┬─┬┬─┬─╥─┬─┬┬─┬─╥─┬─┬┬─┬┬─┬─┐
5
+ │ │ ││ │ ║ │ ││ ││ │ ║ │ ││ │ ║ │ ││ ││ │ │
6
+ │ │X││X│ ║ │X││X││X│ ║ │X││X│ ║ │X││X││X│ │
7
+ │ │X││X│ ║ │X││X││X│ ║ │X││X│ ║ │X││X││X│ │
8
+ │ ┕╥┙┕╥┙ ║ ┕╥┙┕╥┙┕╥┙ ║ ┕╥┙┕╥┙ ║ ┕╥┙┕╥┙┕╥┙ │
9
+ │XX║XX║XX║XX║XX║XX║XX║XX║XX║XX║XX║XX║XX║XX│
10
+ └──╨──╨──╨──╨──╨──╨──╨──╨──╨──╨──╨──╨──╨──┘
11
+ ASCII
12
+
13
+ class << self
14
+ def render_intervals(notes, ref_note)
15
+ output = place_black_notes(Paint[PIANO_TEMPLATE, 'gray'], notes, ref_note)
16
+ place_white_notes(output, notes, ref_note)
17
+ end
18
+
19
+ def place_white_notes(input, notes, ref_note)
20
+ white_notes = Scale.major.notes
21
+ i = 0
22
+ output_array = input.split("\n")
23
+ output_array[5].gsub!('XX') do |match|
24
+ note = white_notes[i%7]
25
+ interval_name = (note - ref_note).name
26
+ i += 1
27
+ notes.map(&:name).include?(note.name) ? Paint[interval_name, 'red'] : ' '
28
+ end
29
+
30
+ output_array.join("\n")
31
+ end
32
+
33
+ def place_black_notes(input, notes, ref_note)
34
+ black_notes = Scale.pentatonic_major('C#',4).notes
35
+ output_array = input.split("\n")
36
+
37
+ i = 0
38
+ output_array[2].gsub!('X') do |match|
39
+ note = black_notes[i%5]
40
+ interval_name = (note - ref_note).name
41
+ i += 1
42
+ notes.map(&:name).include?(note.name) ? Paint[interval_name[0], 'red'] : ' '
43
+ end
44
+
45
+ i = 0
46
+ output_array[3].gsub!('X') do |match|
47
+ note = black_notes[i%5]
48
+ interval_name = (black_notes[i%5] - ref_note).name
49
+ i += 1
50
+ notes.map(&:name).include?(note.name) ? Paint[interval_name[1], 'red'] : ' '
51
+ end
52
+
53
+ output_array.join("\n")
54
+ end
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,27 @@
1
+ module Coltrane
2
+ # It describes a pitch, like E4 or Bb5. It's like a note, but it has an octave
3
+ class Pitch
4
+ attr_reader :number
5
+
6
+ def initialize(pitch)
7
+ case pitch
8
+ when String then @number = number_from_name(pitch)
9
+ when Numeric then @number = pitch
10
+ when Pitch then @number = pitch.number
11
+ end
12
+ end
13
+
14
+ def number_from_name(pitch_string)
15
+ _, note, octaves = pitch_string.match(/(.*)(\d)/).to_a
16
+ Note.new(note).number + 12 * octaves.to_i
17
+ end
18
+
19
+ def name
20
+ "#{note.name}#{number / 12}"
21
+ end
22
+
23
+ def note
24
+ Note.new(number)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,4 @@
1
+ module Coltrane
2
+ class Progression
3
+ end
4
+ end
@@ -0,0 +1,115 @@
1
+ module Qualities
2
+ CHORD_QUALITIES = {
3
+ "5" => [0, 7],
4
+ "Msus2" => [0, 2, 7],
5
+ "dim" => [0, 3, 6],
6
+ "m" => [0, 3, 7],
7
+ "m#5" => [0, 3, 8],
8
+ "Mb5" => [0, 4, 6],
9
+ "M" => [0, 4, 7],
10
+ "" => [0, 4, 7],
11
+ "M#5" => [0, 4, 8],
12
+ "Mb6" => [0, 4, 8],
13
+ "7ndim5" => [0, 4, 10],
14
+ "Msus4" => [0, 5, 7],
15
+ "mb6b9" => [0, 1, 3, 8],
16
+ "addb9" => [0, 1, 4, 7],
17
+ "madd9" => [0, 2, 3, 7],
18
+ "Madd9" => [0, 2, 4, 7],
19
+ "sus24" => [0, 2, 5, 7],
20
+ "M#5add9" => [0, 2, 4, 8],
21
+ "9ndim5" => [0, 2, 4, 10],
22
+ "+add#9" => [0, 3, 4, 8],
23
+ "madd4" => [0, 3, 5, 7],
24
+ "4" => [0, 3, 5, 10],
25
+ "dim7" => [0, 3, 6, 9],
26
+ "m7" => [0, 3, 7, 10],
27
+ "mM7" => [0, 3, 7, 11],
28
+ "m7#5" => [0, 3, 8, 10],
29
+ "7b5" => [0, 4, 6, 10],
30
+ "7" => [0, 4, 7, 10],
31
+ "7#5" => [0, 4, 8, 10],
32
+ "7b13" => [0, 4, 8, 10],
33
+ "M7#5" => [0, 4, 8, 11],
34
+ "M7b6" => [0, 4, 8, 11],
35
+ "M7b5" => [0, 4, 6, 11],
36
+ "M7#5sus4" => [0, 5, 8, 11],
37
+ "7sus4" => [0, 5, 7, 10],
38
+ "7#5sus4" => [0, 5, 8, 10],
39
+ "M7sus4" => [0, 5, 7, 11],
40
+ "M6" => [0, 4, 7, 9],
41
+ "m7b5" => [0, 3, 6, 10],
42
+ "M7" => [0, 4, 7, 11],
43
+ "maj7" => [0, 4, 7, 11],
44
+ "mb6M7" => [0, 3, 8, 11],
45
+ "dimM7" => [0, 3, 6, 11],
46
+ "m6" => [0, 3, 5, 7, 9],
47
+ "m6/9" => [0, 2, 3, 7, 9],
48
+ "M6/9" => [0, 2, 4, 7, 9],
49
+ "M6#11" => [0, 4, 6, 7, 9],
50
+ "m7add11" => [0, 3, 5, 7, 10],
51
+ "dim7M7" => [0, 3, 6, 9, 11],
52
+ "m9" => [0, 2, 3, 7, 10],
53
+ "m9#5" => [0, 2, 3, 8, 10],
54
+ "m9b5" => [0, 2, 3, 6, 10],
55
+ "mM7b6" => [0, 3, 7, 8, 11],
56
+ "mM9" => [0, 2, 3, 7, 11],
57
+ "M7b9" => [0, 1, 4, 7, 11],
58
+ "M9" => [0, 2, 4, 7, 11],
59
+ "M9#5" => [0, 2, 4, 8, 11],
60
+ "M9#5sus4" => [0, 2, 5, 8, 11],
61
+ "M9b5" => [0, 2, 4, 6, 11],
62
+ "M9sus4" => [0, 2, 5, 7, 11],
63
+ "M7#11" => [0, 4, 6, 7, 11],
64
+ "7#9" => [0, 3, 4, 7, 10],
65
+ "7#11" => [0, 4, 6, 7, 10],
66
+ "11" => [0, 2, 5, 7, 10],
67
+ "11b9" => [0, 1, 5, 7, 10],
68
+ "13ndim5" => [0, 2, 4, 9, 10],
69
+ "7#5#9" => [0, 3, 4, 8, 10],
70
+ "7#5b9" => [0, 1, 4, 8, 10],
71
+ "7add6" => [0, 4, 7, 9, 10],
72
+ "7b6" => [0, 4, 7, 8, 10],
73
+ "7b9" => [0, 1, 4, 7, 10],
74
+ "7sus4b9" => [0, 1, 5, 7, 10],
75
+ "9" => [0, 2, 4, 7, 10],
76
+ "9#5" => [0, 2, 4, 8, 10],
77
+ "9b13" => [0, 2, 4, 8, 10],
78
+ "9b5" => [0, 2, 4, 6, 10],
79
+ "9sus4" => [0, 2, 5, 7, 10],
80
+ "M6/9#11" => [0, 2, 4, 6, 7, 9],
81
+ "6/9#11" => [0, 2, 4, 6, 7, 9],
82
+ "9#5#11" => [0, 2, 4, 6, 8, 10],
83
+ "Blues" => [0, 3, 5, 6, 7, 10],
84
+ "m11" => [0, 2, 3, 5, 7, 10],
85
+ "m11#5" => [0, 2, 3, 5, 8, 10],
86
+ "m11b5" => [0, 2, 3, 5, 6, 10],
87
+ "13b5" => [0, 2, 4, 6, 9, 10],
88
+ "13b9" => [0, 1, 4, 7, 9, 10],
89
+ "13sus4" => [0, 2, 5, 7, 9, 10],
90
+ "7#11b13" => [0, 4, 6, 7, 8, 10],
91
+ "7#5b9#11" => [0, 1, 4, 6, 8, 10],
92
+ "7#9#11" => [0, 3, 4, 6, 7, 10],
93
+ "7#9b13" => [0, 3, 4, 7, 8, 10],
94
+ "13#9" => [0, 3, 4, 7, 9, 10],
95
+ "13" => [0, 2, 4, 7, 9, 10],
96
+ "7b9#11" => [0, 1, 4, 6, 7, 10],
97
+ "7b9#9" => [0, 1, 3, 4, 7, 10],
98
+ "7b9b13" => [0, 1, 4, 7, 8, 10],
99
+ "7sus4b9b13" => [0, 1, 5, 7, 8, 10],
100
+ "9#11" => [0, 2, 4, 6, 7, 10],
101
+ "M13" => [0, 2, 4, 7, 9, 11],
102
+ "M7#9#11" => [0, 3, 4, 6, 7, 11],
103
+ "M7add13" => [0, 2, 4, 7, 9, 11],
104
+ "M9#11" => [0, 2, 4, 6, 7, 11],
105
+ "mM9b6" => [0, 2, 3, 7, 8, 11],
106
+ "7b9b13#11" => [0, 1, 4, 6, 7, 8, 10],
107
+ "13b9#11" => [0, 1, 4, 6, 7, 9, 10],
108
+ "9#11b13" => [0, 2, 4, 6, 7, 8, 10],
109
+ "13#11" => [0, 2, 4, 6, 7, 9, 10],
110
+ "M13#11" => [0, 2, 4, 6, 7, 9, 11],
111
+ "m13" => [0, 2, 3, 5, 7, 9, 10],
112
+ "13#9#11" => [0, 3, 4, 6, 7, 9, 10],
113
+ "7#9#11b13" => [0, 3, 4, 6, 7, 8, 10]
114
+ }
115
+ end