coltrane 2.2.1 → 3.0.0.pre

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.
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