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
@@ -0,0 +1,23 @@
1
+ require 'paint'
2
+ require 'color'
3
+
4
+ require 'coltrane/renderers/text_renderer/base_drawer'
5
+ require 'coltrane/renderers/text_renderer/array_drawer'
6
+ require 'coltrane/renderers/text_renderer/hash_drawer'
7
+ require 'coltrane/renderers/text_renderer/theory_note_set_drawer'
8
+ require 'coltrane/renderers/text_renderer/theory_chord_drawer'
9
+ require 'coltrane/renderers/text_renderer/theory_scale_drawer'
10
+ require 'coltrane/renderers/text_renderer/theory_scale_set_drawer'
11
+ require 'coltrane/renderers/text_renderer/theory_progression_drawer'
12
+ require 'coltrane/renderers/text_renderer/theory_progression_set_drawer'
13
+ require 'coltrane/renderers/text_renderer/representation_guitar_note_set_drawer'
14
+ require 'coltrane/renderers/text_renderer/representation_guitar_chord_drawer'
15
+ require 'coltrane/renderers/text_renderer/representation_piano_note_set_drawer'
16
+
17
+ module Coltrane
18
+ module Renderers
19
+ module TextRenderer
20
+ extend Renderer
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,45 @@
1
+ module Coltrane
2
+ module Renderers
3
+ module TextRenderer
4
+ class ArrayDrawer < BaseDrawer
5
+ alias array model
6
+
7
+ def render
8
+ public_send("render_#{layout}")
9
+ end
10
+
11
+ def renders
12
+ @renders ||= array.map {|it| TextRenderer.render(it, **options) }
13
+ end
14
+
15
+ def render_vertical
16
+ renders.join("\n")
17
+ end
18
+
19
+ def render_horizontal
20
+ array
21
+ .each_slice(per_row)
22
+ .map { |row|
23
+ row
24
+ .map { |element|
25
+ TextRenderer.render(element, **options)
26
+ .split("\n")
27
+ .yield_self { |lines|
28
+ lines
29
+ .map { |l| l.gsub(/\e\[(\d+)(;\d+)*m/, '').size }
30
+ .max
31
+ .yield_self { |column_w|
32
+ lines
33
+ .map { |l| l.ljust(column_w) }
34
+ .+([' ' * column_w])
35
+ }
36
+ }
37
+ }
38
+ .transpose
39
+ .map(&:join)
40
+ }.join("\n")
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,20 @@
1
+ module Coltrane
2
+ module Renderers
3
+ module TextRenderer
4
+ class BaseDrawer
5
+ include Paint
6
+ include Color
7
+
8
+ attr_reader :model, :options, :flavor, :layout, :per_row
9
+
10
+ def initialize(model, **options)
11
+ @model = model
12
+ @options = options
13
+ @flavor = options[:flavor] || :notes
14
+ @layout = options[:layout] || :vertical
15
+ @per_row = options[:per_row] || 4
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ module Coltrane
2
+ module Renderers
3
+ module TextRenderer
4
+ class HashDrawer < BaseDrawer
5
+ alias hash model
6
+
7
+ def render
8
+ hash.map { |k, v|
9
+ "#{k}: \n\n" +
10
+ TextRenderer.render(v, **options)
11
+ }.join("\n")
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Coltrane
4
+ module Renderers
5
+ module TextRenderer
6
+ class RepresentationGuitarChordDrawer < BaseDrawer
7
+ alias chord model
8
+
9
+ def chord_height
10
+ chord.max_fret_span
11
+ end
12
+
13
+ def guitar
14
+ chord.guitar
15
+ end
16
+
17
+ def render
18
+ render_top(chord) +
19
+ (chord.lowest_fret..chord.lowest_fret + chord_height)
20
+ .each_with_index.reduce('') do |memo1, (f, y)|
21
+ memo1 +
22
+ ' ' +
23
+ (chord.guitar.strings.size * 2).times.map { |x| base_color border(x, y) }.join('') +
24
+ "\n" +
25
+ chord.guitar.strings.reduce(base_color(f.to_s.ljust(2, ' '))) do |memo2, s|
26
+ memo2 +
27
+ ' ' +
28
+ render_note(chord.guitar_notes.select do |n|
29
+ n.string == s && n.fret == f
30
+ end.any?)
31
+ end +
32
+ " \n"
33
+ end + ' ' +
34
+ (chord.guitar.strings.size * 2).times.map do |x|
35
+ base_color border(x, chord_height + 1)
36
+ end.join('')
37
+ end
38
+
39
+ def border(x, y)
40
+ edge = [guitar.tuning.size * 2 - 2, chord_height + 1]
41
+ x_on_start = x == 0
42
+ y_on_start = y == 0
43
+ x_on_edge = x == edge[0]
44
+ y_on_edge = y == edge[1]
45
+ x_on_middle = (0...edge[0]).cover?(x)
46
+ y_on_middle = (0...edge[1]).cover?(y)
47
+
48
+ if x_on_start && y_on_start then '┍'
49
+ elsif x_on_middle && y_on_start then x.odd? ? '━' : '┯'
50
+ elsif x_on_edge && y_on_start then '┑'
51
+ elsif x_on_start && y_on_middle then '┝'
52
+ elsif x_on_middle && y_on_middle then x.odd? ? '━' : '┿'
53
+ elsif x_on_edge && y_on_middle then '┥'
54
+ elsif x_on_start && y_on_edge then '┕'
55
+ elsif x_on_middle && y_on_edge then x.odd? ? '━' : '┷'
56
+ elsif x_on_edge && y_on_edge then '┙'
57
+ else ' '
58
+ end
59
+ # puts edge.inspect
60
+ # "#{x},#{y} "
61
+ end
62
+
63
+ def base_color(str)
64
+ Paint[str, '#6A4AC2']
65
+ end
66
+
67
+ def highlight(str)
68
+ Paint[str, '#E67831']
69
+ end
70
+
71
+ def alt(str)
72
+ Paint[str, '#2DD380']
73
+ end
74
+
75
+ def render_top(chord)
76
+ chord.guitar.strings.reduce(' ') do |memo, s|
77
+ memo +
78
+ if chord.guitar_notes.select do |n|
79
+ n.string == s && n.fret == 0 end.any?
80
+ highlight '⬤ '
81
+ elsif chord.guitar_notes.select { |n| n.string == s && n.fret.nil? }.any?
82
+ alt 'x '
83
+ else
84
+ ' '
85
+ end
86
+ end + "\n"
87
+ end
88
+
89
+ def render_note(found)
90
+ found ? highlight('⬤') : base_color('│')
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,76 @@
1
+ module Coltrane
2
+ module Renderers
3
+ module TextRenderer
4
+ class RepresentationGuitarNoteSetDrawer < BaseDrawer
5
+ alias guitar_notes model
6
+
7
+ def guitar
8
+ @guitar ||= guitar_notes.guitar
9
+ end
10
+
11
+ def frets
12
+ guitar.frets
13
+ end
14
+
15
+ def render
16
+ [render_notes, render_special_frets].join("\n" * 2)
17
+ end
18
+
19
+ def render_notes
20
+ guitar_notes.strings.map.with_index.map do |string, str_i|
21
+ Array.new(frets + 2) do |i|
22
+ if i.zero?
23
+ Paint[
24
+ string[:pitch].pitch_class.name,
25
+ HSL.new(140 + str_i * 20, 50, 50).html
26
+ ]
27
+ else
28
+ (i - 1)
29
+ .yield_self { |fret|
30
+ (string[:pitch] + fret)
31
+ .yield_self { |pitch|
32
+ if guitar_notes.notes.include?(pitch.pitch_class)
33
+ place_mark(pitch.pitch_class)
34
+ else
35
+ place_empty(str_i)
36
+ end
37
+ }
38
+ .yield_self { |mark| mark + (fret.zero? ? (' |') : '') }
39
+ }
40
+ end
41
+ end.join(' ')
42
+ end.join("\n")
43
+ end
44
+
45
+ def render_special_frets
46
+ ' ' +
47
+ Array.new(frets + 2) do |fret|
48
+ m = guitar.special_frets.include?(fret) ? fret.to_s.rjust(2, 0.to_s) : ' '
49
+ "#{m}#{' ' if fret.zero?}"
50
+ end.join(' ')
51
+ end
52
+
53
+ def place_empty(str_i)
54
+ Paint['--', HSL.new(180 + str_i * 3, 50, 30).html]
55
+ end
56
+
57
+ def place_mark(note)
58
+ mark = case flavor
59
+ when :notes then note.pretty_name.ljust(2, ' ')
60
+ when :intervals then (guitar_notes.root - note).name.ljust(2, '-')
61
+ when :degrees then guitar_notes.notes.degree(note).to_s.rjust(2, '0')
62
+ when :marks then ' ' # '◼◼'
63
+ else raise WrongFlavorError
64
+ end
65
+
66
+ base_hue = (180 + note.integer * 10) % 360 # + 260
67
+ Paint[
68
+ mark,
69
+ HSL.new(0, 0, 100).html,
70
+ HSL.new(base_hue, 100, 30).html
71
+ ]
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,49 @@
1
+ module Coltrane
2
+ module Renderers
3
+ module TextRenderer
4
+ class RepresentationPianoNoteSetDrawer < BaseDrawer
5
+ alias note_set model
6
+
7
+ PIANO_TEMPLATE = <<~ASCII
8
+ ┌─┬─┬┬─┬─╥─┬─┬┬─┬┬─┬─╥─┬─┬┬─┬─╥─┬─┬┬─┬┬─┬─┐
9
+ │ │ ││ │ ║ │ ││ ││ │ ║ │ ││ │ ║ │ ││ ││ │ │
10
+ │ │X││X│ ║ │X││X││X│ ║ │X││X│ ║ │X││X││X│ │
11
+ │ │X││X│ ║ │X││X││X│ ║ │X││X│ ║ │X││X││X│ │
12
+ │ ┕╥┙┕╥┙ ║ ┕╥┙┕╥┙┕╥┙ ║ ┕╥┙┕╥┙ ║ ┕╥┙┕╥┙┕╥┙ │
13
+ │ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ │
14
+ │XX║XX║XX║XX║XX║XX║XX║XX║XX║XX║XX║XX║XX║XX│
15
+ └──╨──╨──╨──╨──╨──╨──╨──╨──╨──╨──╨──╨──╨──┘
16
+ ASCII
17
+
18
+ def render
19
+ PIANO_TEMPLATE.each_line.map.each_with_index do |l, ln|
20
+ case ln
21
+ when 2, 3 then replace_x(l, Representation::Piano.black_notes, 1, ln - 2)
22
+ when 6 then replace_x(l, Representation::Piano.white_notes, 2)
23
+ else l
24
+ end
25
+ end.join
26
+ end
27
+
28
+ private
29
+
30
+ def replace_x(line, notes, size, index = 0)
31
+ line.gsub('X' * size).with_index do |_match, i|
32
+ note = notes[i % notes.size]
33
+ next ' ' * size unless note_set.include?(note)
34
+ Paint[replacer(note)[size == 2 ? 0..2 : index], 'red']
35
+ end
36
+ end
37
+
38
+ def replacer(note)
39
+ case flavor
40
+ when :intervals then (note_set.root - note).name
41
+ when :marks then '◼ '
42
+ when :degrees then note_set.notes.degree(note).to_s.rjust(2, '0')
43
+ when :notes then note.pretty_name.to_s.ljust(2, "\u266E")
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,14 @@
1
+ module Coltrane
2
+ module Renderers
3
+ module TextRenderer
4
+ class TheoryChordDrawer < BaseDrawer
5
+ alias chord model
6
+
7
+ def render
8
+ "#{chord.name}: ".ljust(5) +
9
+ TextRenderer.render(chord.notes, **options)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,17 @@
1
+ module Coltrane
2
+ module Renderers
3
+ module TextRenderer
4
+ class TheoryNoteSetDrawer < BaseDrawer
5
+ def render
6
+ case flavor
7
+ when :marks, :notes, :degrees
8
+ model.pretty_names.join(' ')
9
+ when :intervals
10
+ model.map { |n| (model.first - n).name }.join(' ')
11
+ else raise WrongFlavorError
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ module Coltrane
2
+ module Renderers
3
+ module TextRenderer
4
+ class TheoryProgressionDrawer < BaseDrawer
5
+ alias progression model
6
+
7
+ def render
8
+ TextRenderer.render(progression.chords, **options)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ module Coltrane
2
+ module Renderers
3
+ module TextRenderer
4
+ class TheoryProgressionSetDrawer < BaseDrawer
5
+ alias progression_set model
6
+
7
+ def render
8
+ progression_set.map do |progression|
9
+ "#{progression.notation.ljust(notation_width + 1, ' ')} in " \
10
+ "#{progression.scale} (#{progression.notes_out.size} notes out)"
11
+ end
12
+ .join("\n")
13
+ end
14
+
15
+ def notation_width
16
+ @notation_width ||=
17
+ progression_set.map(&:notation).map(&:size).max
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ module Coltrane
2
+ module Renderers
3
+ module TextRenderer
4
+ class TheoryScaleDrawer < BaseDrawer
5
+ alias scale model
6
+
7
+ def render
8
+ TextRenderer.render(scale.notes, **options)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,27 @@
1
+ module Coltrane
2
+ module Renderers
3
+ module TextRenderer
4
+ class TheoryScaleSetDrawer < BaseDrawer
5
+ alias scale_set model
6
+
7
+ def render
8
+ output = []
9
+ scale_width = scale_set.results.keys.map(&:size).max
10
+ scale_set.results.each do |name, scales_by_tone|
11
+ output << name.ljust(scale_width + 1, ' ')
12
+ scales_by_tone.each do |tone_number, notes|
13
+ p = (notes.size.to_f / scale_set.searched_notes.size) * 100
14
+ l = p == 100 ? p : (p + 20) * 0.4
15
+ und = p == 100 ? :underline : nil
16
+ color = Color::HSL.new(30, p, l / 2).html
17
+ output << Paint["#{Theory::Note[tone_number].name}(#{notes.size})", color, und]
18
+ output << ' '
19
+ end
20
+ output << "\n"
21
+ end
22
+ output.join
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end