coltrane 2.2.1 → 3.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +16 -1
  3. data/CHANGELOG.md +11 -0
  4. data/Gemfile.lock +25 -2
  5. data/README.md +3 -0
  6. data/bin/console +6 -2
  7. data/coltrane.gemspec +2 -1
  8. data/exe/coltrane +14 -224
  9. data/lib/coltrane.rb +3 -50
  10. data/lib/coltrane/commands.rb +14 -0
  11. data/lib/coltrane/commands/chords.rb +77 -0
  12. data/lib/coltrane/commands/command.rb +45 -0
  13. data/lib/coltrane/commands/common_chords.rb +33 -0
  14. data/lib/coltrane/commands/errors.rb +44 -0
  15. data/lib/coltrane/commands/find_progression.rb +28 -0
  16. data/lib/coltrane/commands/find_scale.rb +39 -0
  17. data/lib/coltrane/commands/notes.rb +44 -0
  18. data/lib/coltrane/commands/progression.rb +27 -0
  19. data/lib/{cli → coltrane/commands}/representation.rb +0 -0
  20. data/lib/coltrane/commands/scale.rb +46 -0
  21. data/lib/coltrane/renderers.rb +6 -0
  22. data/lib/coltrane/renderers/renderer.rb +42 -0
  23. data/lib/coltrane/renderers/text_renderer.rb +23 -0
  24. data/lib/coltrane/renderers/text_renderer/array_drawer.rb +45 -0
  25. data/lib/coltrane/renderers/text_renderer/base_drawer.rb +20 -0
  26. data/lib/coltrane/renderers/text_renderer/hash_drawer.rb +16 -0
  27. data/lib/coltrane/renderers/text_renderer/representation_guitar_chord_drawer.rb +95 -0
  28. data/lib/coltrane/renderers/text_renderer/representation_guitar_note_set_drawer.rb +76 -0
  29. data/lib/coltrane/renderers/text_renderer/representation_piano_note_set_drawer.rb +49 -0
  30. data/lib/coltrane/renderers/text_renderer/theory_chord_drawer.rb +14 -0
  31. data/lib/coltrane/renderers/text_renderer/theory_note_set_drawer.rb +17 -0
  32. data/lib/coltrane/renderers/text_renderer/theory_progression_drawer.rb +13 -0
  33. data/lib/coltrane/renderers/text_renderer/theory_progression_set_drawer.rb +22 -0
  34. data/lib/coltrane/renderers/text_renderer/theory_scale_drawer.rb +13 -0
  35. data/lib/coltrane/renderers/text_renderer/theory_scale_set_drawer.rb +27 -0
  36. data/lib/coltrane/representation.rb +12 -0
  37. data/lib/coltrane/representation/guitar.rb +34 -0
  38. data/lib/coltrane/representation/guitar/chord.rb +180 -0
  39. data/lib/coltrane/representation/guitar/note.rb +26 -0
  40. data/lib/coltrane/representation/guitar/note_set.rb +35 -0
  41. data/lib/coltrane/representation/guitar/string.rb +31 -0
  42. data/lib/coltrane/representation/guitar_like_instruments.rb +21 -0
  43. data/lib/coltrane/representation/piano.rb +36 -0
  44. data/lib/coltrane/representation/piano/note_set.rb +22 -0
  45. data/lib/{coltrane_synth.rb → coltrane/synth.rb.rb} +0 -0
  46. data/lib/{coltrane_synth → coltrane/synth}/base.rb +0 -0
  47. data/lib/{coltrane_synth → coltrane/synth}/synth.rb +0 -0
  48. data/lib/coltrane/theory.rb +54 -0
  49. data/lib/coltrane/theory/cadence.rb +9 -0
  50. data/lib/coltrane/{changes.rb → theory/changes.rb} +0 -0
  51. data/lib/coltrane/theory/chord.rb +101 -0
  52. data/lib/coltrane/theory/chord_quality.rb +113 -0
  53. data/lib/coltrane/theory/chord_substitutions.rb +11 -0
  54. data/lib/coltrane/theory/circle_of_fifths.rb +33 -0
  55. data/lib/coltrane/theory/classic_scales.rb +113 -0
  56. data/lib/coltrane/theory/diatonic_scale.rb +38 -0
  57. data/lib/coltrane/theory/errors.rb +97 -0
  58. data/lib/coltrane/theory/frequency.rb +52 -0
  59. data/lib/coltrane/theory/frequency_interval.rb +83 -0
  60. data/lib/coltrane/theory/interval.rb +209 -0
  61. data/lib/coltrane/theory/interval_class.rb +212 -0
  62. data/lib/coltrane/theory/interval_sequence.rb +157 -0
  63. data/lib/coltrane/theory/key.rb +18 -0
  64. data/lib/coltrane/{mode.rb → theory/mode.rb} +0 -0
  65. data/lib/coltrane/theory/notable_progressions.rb +30 -0
  66. data/lib/coltrane/theory/note.rb +104 -0
  67. data/lib/coltrane/theory/note_set.rb +101 -0
  68. data/lib/coltrane/theory/pitch.rb +94 -0
  69. data/lib/coltrane/theory/pitch_class.rb +154 -0
  70. data/lib/coltrane/theory/progression.rb +81 -0
  71. data/lib/coltrane/theory/progression_set.rb +18 -0
  72. data/lib/coltrane/{qualities.rb → theory/qualities.rb} +0 -0
  73. data/lib/coltrane/theory/roman_chord.rb +114 -0
  74. data/lib/coltrane/theory/scale.rb +161 -0
  75. data/lib/coltrane/theory/scale_search_result.rb +6 -0
  76. data/lib/coltrane/theory/scale_set.rb +40 -0
  77. data/lib/coltrane/theory/voicing.rb +41 -0
  78. data/lib/coltrane/version.rb +1 -1
  79. metadata +88 -63
  80. data/bin/rails +0 -17
  81. data/data/qualities.yml +0 -83
  82. data/db/cache.sqlite3 +0 -0
  83. data/db/cache_test.sqlite3 +0 -0
  84. data/db/config.yml +0 -11
  85. data/lib/cli.rb +0 -24
  86. data/lib/cli/bass_guitar.rb +0 -12
  87. data/lib/cli/chord.rb +0 -39
  88. data/lib/cli/config.rb +0 -39
  89. data/lib/cli/errors.rb +0 -46
  90. data/lib/cli/guitar.rb +0 -67
  91. data/lib/cli/guitar_chords.rb +0 -122
  92. data/lib/cli/notes.rb +0 -20
  93. data/lib/cli/piano.rb +0 -57
  94. data/lib/cli/scale.rb +0 -53
  95. data/lib/cli/text.rb +0 -16
  96. data/lib/cli/ukulele.rb +0 -14
  97. data/lib/coltrane/cache.rb +0 -43
  98. data/lib/coltrane/cadence.rb +0 -7
  99. data/lib/coltrane/chord.rb +0 -89
  100. data/lib/coltrane/chord_quality.rb +0 -111
  101. data/lib/coltrane/chord_substitutions.rb +0 -9
  102. data/lib/coltrane/circle_of_fifths.rb +0 -31
  103. data/lib/coltrane/classic_scales.rb +0 -94
  104. data/lib/coltrane/diatonic_scale.rb +0 -36
  105. data/lib/coltrane/errors.rb +0 -95
  106. data/lib/coltrane/frequency.rb +0 -50
  107. data/lib/coltrane/frequency_interval.rb +0 -81
  108. data/lib/coltrane/interval.rb +0 -208
  109. data/lib/coltrane/interval_class.rb +0 -210
  110. data/lib/coltrane/interval_sequence.rb +0 -155
  111. data/lib/coltrane/key.rb +0 -16
  112. data/lib/coltrane/notable_progressions.rb +0 -28
  113. data/lib/coltrane/note.rb +0 -98
  114. data/lib/coltrane/note_set.rb +0 -89
  115. data/lib/coltrane/pitch.rb +0 -92
  116. data/lib/coltrane/pitch_class.rb +0 -148
  117. data/lib/coltrane/progression.rb +0 -74
  118. data/lib/coltrane/roman_chord.rb +0 -112
  119. data/lib/coltrane/scale.rb +0 -154
  120. data/lib/coltrane/unordered_interval_class.rb +0 -7
  121. data/lib/coltrane/voicing.rb +0 -39
  122. data/lib/coltrane_game/question.rb +0 -7
  123. data/lib/coltrane_instruments.rb +0 -7
  124. data/lib/coltrane_instruments/guitar.rb +0 -10
  125. data/lib/coltrane_instruments/guitar/base.rb +0 -29
  126. data/lib/coltrane_instruments/guitar/chord.rb +0 -170
  127. data/lib/coltrane_instruments/guitar/note.rb +0 -24
  128. data/lib/coltrane_instruments/guitar/string.rb +0 -29
  129. data/lib/os.rb +0 -21
@@ -1,155 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Coltrane
4
- # It describes a sequence of intervals
5
- class IntervalSequence
6
- extend Forwardable
7
- attr_reader :intervals
8
-
9
- def_delegators :@intervals, :map, :each, :[], :size,
10
- :reduce, :delete, :reject!, :delete_if, :detect, :to_a
11
-
12
- def initialize(*intervals, notes: nil, relative_intervals: nil)
13
- if intervals.any?
14
- @intervals = if intervals.first.is_a?(Interval)
15
- intervals
16
- else
17
- intervals.map { |i| Interval[i] }
18
- end
19
-
20
- elsif notes
21
- notes = NoteSet[*notes] if notes.is_a?(Array)
22
- @intervals = intervals_from_notes(notes)
23
- elsif relative_intervals
24
- @relative_intervals = relative_intervals
25
- @intervals = intervals_from_relative_intervals(relative_intervals)
26
- else
27
- raise WrongKeywordsError,
28
- 'Provide: [notes:] || [intervals:] || [relative_intervals:]'
29
- end
30
- end
31
-
32
- Interval.all_including_compound_and_altered.each do |interval|
33
- # Creates methods such as major_third, returning it if it finds
34
- define_method(interval.full_name.underscore.to_s) { find(interval) }
35
- # Creates methods such as has_major_third?, returning a boolean
36
- define_method("has_#{interval.full_name.underscore}?") { has?(interval) }
37
- end
38
-
39
- Interval.distances_names.map(&:underscore).each_with_index do |distance, i|
40
- # Creates methods such as has_third?, returning a boolean
41
- define_method("has_#{distance}?") { !!find_by_distance(i + 1) }
42
- # Creates methods such third, returning any third it finds
43
- define_method(distance.to_s) { find_by_distance(i + 1) }
44
- # Creates methods such third!, returning thirds that arent aug or dim
45
- define_method("#{distance}!") { find_by_distance(i + 1, false) }
46
- end
47
-
48
- instance_eval { alias [] new }
49
-
50
- def relative_intervals
51
- intervals_semitones[1..-1].each_with_index.map do |n, i|
52
- if i.zero?
53
- n
54
- elsif i < intervals_semitones.size
55
- n - intervals_semitones[i]
56
- end
57
- end + [12 - intervals_semitones.last]
58
- end
59
-
60
- def names
61
- intervals.map(&:name)
62
- end
63
-
64
- def find(interval)
65
- interval.clone if detect { |i| interval == i }
66
- end
67
-
68
- def has?(interval)
69
- !!find(interval)
70
- end
71
-
72
- def find_by_distance(n, accept_altered = true)
73
- strategy = (accept_altered ? :as : :as!)
74
- map { |interval| interval.send(strategy, n) }
75
- .compact
76
- .sort_by { |i| i.alteration.abs }
77
- .first
78
- end
79
-
80
- alias interval_names names
81
-
82
- def all
83
- intervals
84
- end
85
-
86
- def [](x)
87
- intervals[x]
88
- end
89
-
90
- def shift(ammount)
91
- self.class.new(*intervals.map do |i|
92
- (i.semitones + ammount) % 12
93
- end)
94
- end
95
-
96
- def zero_it
97
- shift(-intervals.first.semitones)
98
- end
99
-
100
- def inversion(index)
101
- self.class.new(*intervals.rotate(index)).zero_it
102
- end
103
-
104
- def next_inversion
105
- inversion(index + 1)
106
- end
107
-
108
- def previous_inversion
109
- inversion(index - 1)
110
- end
111
-
112
- def inversions
113
- Array.new(intervals.length) { |i| inversion(i) }
114
- end
115
-
116
- def intervals_semitones
117
- map(&:semitones)
118
- end
119
-
120
- def names
121
- map(&:name)
122
- end
123
-
124
- def full_names
125
- map(&:full_name)
126
- end
127
-
128
- def notes_for(root_note)
129
- NoteSet[
130
- *intervals.reduce([]) do |memo, interval|
131
- memo + [root_note + interval]
132
- end
133
- ]
134
- end
135
-
136
- def &(other)
137
- case other
138
- when Array then intervals & other
139
- when IntervalSequence then intervals & other.semitones
140
- end
141
- end
142
-
143
- private
144
-
145
- def intervals_from_relative_intervals(relative_intervals)
146
- relative_intervals[0..-2].reduce([Interval[0]]) do |memo, d|
147
- memo + [memo.last + d]
148
- end
149
- end
150
-
151
- def intervals_from_notes(notes)
152
- notes.map { |n| notes.root - n }.sort_by(&:semitones)
153
- end
154
- end
155
- end
data/lib/coltrane/key.rb DELETED
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Coltrane
4
- class Key < DiatonicScale
5
- KEY_REGEX = /([A-G][#b]?)([mM]?)/
6
-
7
- def initialize(notation)
8
- _, note, s = *notation.match(KEY_REGEX)
9
- super(note, major: s != 'm')
10
- end
11
-
12
- def self.[](notation)
13
- new(notation)
14
- end
15
- end
16
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Coltrane
4
- # This module takes care of adding to progressions knowledge that is more
5
- # based on common standards and practices.
6
- module NotableProgressions
7
- PROGRESSIONS = {
8
- 'Pop' => ['I-V-vi-IV', :major],
9
- 'Jazzy Pop' => ['IM7-V7-vi7-IVM7', :major],
10
- 'Jazz' => ['ii7-V7-I7', :major],
11
- 'Jazz Minor' => ['ii7-V7-i7', :major],
12
- 'Blues' => ['IM7-IV7-I7-V7-IV7-I7', :major],
13
- 'Jazz Blues' => ['I7-IV7-I7-V7-IV7-I7', :major],
14
- 'Fifties' => ['I-vi-IV-V', :major],
15
- 'Circle' => ['vi-ii-V-I', :major],
16
- 'Tune Up' => ['ii7-V7-IM7-i7-IV7-IVM7-VIIM7', :minor]
17
- }.freeze
18
-
19
- PROGRESSIONS.each do |name, values|
20
- notation, scale_name = values
21
- define_method name.underscore do |note|
22
- note = note.is_a?(Note) ? note : Note[note]
23
- scale = Scale.public_send(scale_name, note)
24
- new(notation, scale: scale)
25
- end
26
- end
27
- end
28
- end
data/lib/coltrane/note.rb DELETED
@@ -1,98 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Coltrane
4
- # Notes are different ways of calling pitch classes. In the context of equal
5
- # tempered scales, they're more like a conceptual subject for
6
- # matters of convention than an actual thing.
7
- #
8
- # Take for example A# and Bb. Those are different notes. Nevertheless, in the
9
- # context of equal tempered scales they represent pretty much the same
10
- # frequency.
11
- #
12
- # The theory of notes have changed too much in the course of time, which
13
- # lead us with a lot of conventions and strategies when dealing with music.
14
- # That's what this class is for.
15
- class Note < PitchClass
16
- attr_reader :alteration
17
-
18
- ALTERATIONS = {
19
- 'b' => -1,
20
- '#' => 1
21
- }.freeze
22
-
23
- def initialize(arg)
24
- note_name = case arg
25
- when String then arg
26
- when PitchClass then arg.true_notation
27
- when Numeric, Frequency then PitchClass.new(arg).true_notation
28
- else raise(WrongArgumentsError, arg)
29
- end
30
-
31
- chars = note_name.chars
32
- letter = chars.shift
33
- raise InvalidNoteLetterError, arg unless ('A'..'G').cover?(letter)
34
- @alteration = chars.reduce(0) do |alt, symbol|
35
- raise InvalidNoteLetterError, arg unless ALTERATIONS.include?(symbol)
36
- alt + ALTERATIONS[symbol]
37
- end
38
- super((PitchClass[letter].integer + @alteration) % PitchClass.size)
39
- end
40
-
41
- def self.[](arg)
42
- new(arg)
43
- end
44
-
45
- def name
46
- "#{base_pitch_class}#{accidents}".gsub(/#b|b#/, '')
47
- end
48
-
49
- def base_pitch_class
50
- PitchClass[integer - alteration]
51
- end
52
-
53
- def alteration=(a)
54
- @alteration = a unless PitchClass[integer - a].accidental?
55
- end
56
-
57
- def alter(x)
58
- Note.new(name).tap { |n| n.alteration = x }
59
- end
60
-
61
- def sharp?
62
- alteration == 1
63
- end
64
-
65
- def double_sharp?
66
- alteration == 2
67
- end
68
-
69
- def flat?
70
- alteration == -1
71
- end
72
-
73
- def double_flat?
74
- alteration == -2
75
- end
76
-
77
- def natural?
78
- alteration == 0
79
- end
80
-
81
- def accidents
82
- (@alteration > 0 ? '#' : 'b') * alteration.abs
83
- end
84
-
85
- def -(other)
86
- super(other).yield_self { |r| r.is_a?(Note) ? r.alter(alteration) : r }
87
- end
88
-
89
- def +(other)
90
- super(other).yield_self { |r| r.is_a?(Note) ? r.alter(alteration) : r }
91
- end
92
-
93
- def as(letter)
94
- a = (Note[letter] - self)
95
- alter([a.semitones, -(-a).semitones].min_by(&:abs))
96
- end
97
- end
98
- end
@@ -1,89 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Coltrane
4
- # It describes a set of notes
5
- class NoteSet
6
- extend Forwardable
7
-
8
- def_delegators :@notes, :first, :each, :size, :map, :reduce, :index,
9
- :[], :index, :empty?, :permutation, :include?, :<<, :any?,
10
- :count, :rotate
11
-
12
- attr_reader :notes
13
-
14
- alias root first
15
- alias all notes
16
-
17
- def self.[](*notes)
18
- new(notes)
19
- end
20
-
21
- def initialize(arg)
22
- @notes =
23
- case arg
24
- when NoteSet then arg.notes
25
- when Array then arg.compact.map { |n| n.is_a?(PitchClass) ? n : Note[n] }.uniq
26
- else raise InvalidNotesError, arg
27
- end
28
- end
29
-
30
- def &(other)
31
- NoteSet[*(notes & other.notes)]
32
- end
33
-
34
- def degree(note)
35
- index(note) + 1
36
- end
37
-
38
- def +(other)
39
- case other
40
- when Note then NoteSet[*(notes + [other])]
41
- when NoteSet then NoteSet[*notes, *other.notes]
42
- when Interval then NoteSet[*notes.map { |n| n + other }]
43
- end
44
- end
45
-
46
- def -(other)
47
- case other
48
- when NoteSet then NoteSet[*(notes - other.notes)]
49
- when Interval then NoteSet[*notes.map { |n| n - other }]
50
- end
51
- end
52
-
53
- def pretty_names
54
- map(&:pretty_name)
55
- end
56
-
57
- def names
58
- map(&:name)
59
- end
60
-
61
- def integers
62
- map(&:integer)
63
- end
64
-
65
- def accidentals
66
- count(&:accidental?)
67
- end
68
-
69
- def sharps
70
- count(&:sharp?)
71
- end
72
-
73
- def flats
74
- count(&:flat?)
75
- end
76
-
77
- def alter(alteration)
78
- NoteSet[*map { |n| n.alter(alteration) }]
79
- end
80
-
81
- def alter_accidentals(alteration)
82
- NoteSet[*map { |n| n.alter(alteration) if n.accidental? }]
83
- end
84
-
85
- def interval_sequence
86
- IntervalSequence.new(notes: self)
87
- end
88
- end
89
- end
@@ -1,92 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Coltrane
4
- # It describes a pitch, like E4 or Bb5. It's like a note, but it has an octave
5
- class Pitch
6
- attr_reader :integer
7
-
8
- def initialize(notation_arg = nil,
9
- note: nil,
10
- octave: nil,
11
- notation: nil,
12
- frequency: nil)
13
-
14
- @integer = begin
15
- if (n = notation_arg || notation)
16
- n.is_a?(Integer) ? n : integer_from_notation(n)
17
- elsif note && octave
18
- integer_from_note_and_octave(Note[note], octave)
19
- elsif frequency
20
- integer_from_frequency(frequency)
21
- else
22
- raise(InvalidArgumentsError)
23
- end
24
- end
25
- end
26
-
27
- def self.[](*args)
28
- new *args
29
- end
30
-
31
- def scientific_notation
32
- "#{pitch_class}#{octave}"
33
- end
34
-
35
- def pitch_class
36
- PitchClass[integer]
37
- end
38
-
39
- def octave
40
- (integer / 12) - 1
41
- end
42
-
43
- alias notation scientific_notation
44
- alias name scientific_notation
45
- alias to_s scientific_notation
46
-
47
- alias hash integer
48
- alias midi integer
49
-
50
- def ==(other)
51
- integer == other.integer
52
- end
53
-
54
- def frequency
55
- pitch_class.frequency.octave(octave)
56
- end
57
-
58
- alias eql? ==
59
- alias eq ==
60
-
61
- def +(other)
62
- case other
63
- when Integer then Pitch[integer + other]
64
- end
65
- end
66
-
67
- def -(other)
68
- case other
69
- when Integer then Pitch[integer - other]
70
- end
71
- end
72
-
73
- private
74
-
75
- def integer_from_notation(the_notation)
76
- _, n, o = *the_notation.match(/(\D+)(\d+)/)
77
- integer_from_note_and_octave(Note[n], o)
78
- end
79
-
80
- def integer_from_note_and_octave(p, o)
81
- 12 * (o.to_i + 1) + p.integer
82
- end
83
-
84
- def integer_from_frequency(f)
85
- octave_from_frequency(f) * 12 + PitchClass.new(frequency: f).integer
86
- end
87
-
88
- def octave_from_frequency(f)
89
- Math.log(f.to_f / PitchClass['C'].frequency.to_f, 2).ceil
90
- end
91
- end
92
- end