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.
- checksums.yaml +4 -4
- data/.travis.yml +16 -1
- data/CHANGELOG.md +11 -0
- data/Gemfile.lock +25 -2
- data/README.md +3 -0
- data/bin/console +6 -2
- data/coltrane.gemspec +2 -1
- data/exe/coltrane +14 -224
- data/lib/coltrane.rb +3 -50
- data/lib/coltrane/commands.rb +14 -0
- data/lib/coltrane/commands/chords.rb +77 -0
- data/lib/coltrane/commands/command.rb +45 -0
- data/lib/coltrane/commands/common_chords.rb +33 -0
- data/lib/coltrane/commands/errors.rb +44 -0
- data/lib/coltrane/commands/find_progression.rb +28 -0
- data/lib/coltrane/commands/find_scale.rb +39 -0
- data/lib/coltrane/commands/notes.rb +44 -0
- data/lib/coltrane/commands/progression.rb +27 -0
- data/lib/{cli → coltrane/commands}/representation.rb +0 -0
- data/lib/coltrane/commands/scale.rb +46 -0
- data/lib/coltrane/renderers.rb +6 -0
- data/lib/coltrane/renderers/renderer.rb +42 -0
- data/lib/coltrane/renderers/text_renderer.rb +23 -0
- data/lib/coltrane/renderers/text_renderer/array_drawer.rb +45 -0
- data/lib/coltrane/renderers/text_renderer/base_drawer.rb +20 -0
- data/lib/coltrane/renderers/text_renderer/hash_drawer.rb +16 -0
- data/lib/coltrane/renderers/text_renderer/representation_guitar_chord_drawer.rb +95 -0
- data/lib/coltrane/renderers/text_renderer/representation_guitar_note_set_drawer.rb +76 -0
- data/lib/coltrane/renderers/text_renderer/representation_piano_note_set_drawer.rb +49 -0
- data/lib/coltrane/renderers/text_renderer/theory_chord_drawer.rb +14 -0
- data/lib/coltrane/renderers/text_renderer/theory_note_set_drawer.rb +17 -0
- data/lib/coltrane/renderers/text_renderer/theory_progression_drawer.rb +13 -0
- data/lib/coltrane/renderers/text_renderer/theory_progression_set_drawer.rb +22 -0
- data/lib/coltrane/renderers/text_renderer/theory_scale_drawer.rb +13 -0
- data/lib/coltrane/renderers/text_renderer/theory_scale_set_drawer.rb +27 -0
- data/lib/coltrane/representation.rb +12 -0
- data/lib/coltrane/representation/guitar.rb +34 -0
- data/lib/coltrane/representation/guitar/chord.rb +180 -0
- data/lib/coltrane/representation/guitar/note.rb +26 -0
- data/lib/coltrane/representation/guitar/note_set.rb +35 -0
- data/lib/coltrane/representation/guitar/string.rb +31 -0
- data/lib/coltrane/representation/guitar_like_instruments.rb +21 -0
- data/lib/coltrane/representation/piano.rb +36 -0
- data/lib/coltrane/representation/piano/note_set.rb +22 -0
- data/lib/{coltrane_synth.rb → coltrane/synth.rb.rb} +0 -0
- data/lib/{coltrane_synth → coltrane/synth}/base.rb +0 -0
- data/lib/{coltrane_synth → coltrane/synth}/synth.rb +0 -0
- data/lib/coltrane/theory.rb +54 -0
- data/lib/coltrane/theory/cadence.rb +9 -0
- data/lib/coltrane/{changes.rb → theory/changes.rb} +0 -0
- data/lib/coltrane/theory/chord.rb +101 -0
- data/lib/coltrane/theory/chord_quality.rb +113 -0
- data/lib/coltrane/theory/chord_substitutions.rb +11 -0
- data/lib/coltrane/theory/circle_of_fifths.rb +33 -0
- data/lib/coltrane/theory/classic_scales.rb +113 -0
- data/lib/coltrane/theory/diatonic_scale.rb +38 -0
- data/lib/coltrane/theory/errors.rb +97 -0
- data/lib/coltrane/theory/frequency.rb +52 -0
- data/lib/coltrane/theory/frequency_interval.rb +83 -0
- data/lib/coltrane/theory/interval.rb +209 -0
- data/lib/coltrane/theory/interval_class.rb +212 -0
- data/lib/coltrane/theory/interval_sequence.rb +157 -0
- data/lib/coltrane/theory/key.rb +18 -0
- data/lib/coltrane/{mode.rb → theory/mode.rb} +0 -0
- data/lib/coltrane/theory/notable_progressions.rb +30 -0
- data/lib/coltrane/theory/note.rb +104 -0
- data/lib/coltrane/theory/note_set.rb +101 -0
- data/lib/coltrane/theory/pitch.rb +94 -0
- data/lib/coltrane/theory/pitch_class.rb +154 -0
- data/lib/coltrane/theory/progression.rb +81 -0
- data/lib/coltrane/theory/progression_set.rb +18 -0
- data/lib/coltrane/{qualities.rb → theory/qualities.rb} +0 -0
- data/lib/coltrane/theory/roman_chord.rb +114 -0
- data/lib/coltrane/theory/scale.rb +161 -0
- data/lib/coltrane/theory/scale_search_result.rb +6 -0
- data/lib/coltrane/theory/scale_set.rb +40 -0
- data/lib/coltrane/theory/voicing.rb +41 -0
- data/lib/coltrane/version.rb +1 -1
- metadata +88 -63
- data/bin/rails +0 -17
- data/data/qualities.yml +0 -83
- data/db/cache.sqlite3 +0 -0
- data/db/cache_test.sqlite3 +0 -0
- data/db/config.yml +0 -11
- data/lib/cli.rb +0 -24
- data/lib/cli/bass_guitar.rb +0 -12
- data/lib/cli/chord.rb +0 -39
- data/lib/cli/config.rb +0 -39
- data/lib/cli/errors.rb +0 -46
- data/lib/cli/guitar.rb +0 -67
- data/lib/cli/guitar_chords.rb +0 -122
- data/lib/cli/notes.rb +0 -20
- data/lib/cli/piano.rb +0 -57
- data/lib/cli/scale.rb +0 -53
- data/lib/cli/text.rb +0 -16
- data/lib/cli/ukulele.rb +0 -14
- data/lib/coltrane/cache.rb +0 -43
- data/lib/coltrane/cadence.rb +0 -7
- data/lib/coltrane/chord.rb +0 -89
- data/lib/coltrane/chord_quality.rb +0 -111
- data/lib/coltrane/chord_substitutions.rb +0 -9
- data/lib/coltrane/circle_of_fifths.rb +0 -31
- data/lib/coltrane/classic_scales.rb +0 -94
- data/lib/coltrane/diatonic_scale.rb +0 -36
- data/lib/coltrane/errors.rb +0 -95
- data/lib/coltrane/frequency.rb +0 -50
- data/lib/coltrane/frequency_interval.rb +0 -81
- data/lib/coltrane/interval.rb +0 -208
- data/lib/coltrane/interval_class.rb +0 -210
- data/lib/coltrane/interval_sequence.rb +0 -155
- data/lib/coltrane/key.rb +0 -16
- data/lib/coltrane/notable_progressions.rb +0 -28
- data/lib/coltrane/note.rb +0 -98
- data/lib/coltrane/note_set.rb +0 -89
- data/lib/coltrane/pitch.rb +0 -92
- data/lib/coltrane/pitch_class.rb +0 -148
- data/lib/coltrane/progression.rb +0 -74
- data/lib/coltrane/roman_chord.rb +0 -112
- data/lib/coltrane/scale.rb +0 -154
- data/lib/coltrane/unordered_interval_class.rb +0 -7
- data/lib/coltrane/voicing.rb +0 -39
- data/lib/coltrane_game/question.rb +0 -7
- data/lib/coltrane_instruments.rb +0 -7
- data/lib/coltrane_instruments/guitar.rb +0 -10
- data/lib/coltrane_instruments/guitar/base.rb +0 -29
- data/lib/coltrane_instruments/guitar/chord.rb +0 -170
- data/lib/coltrane_instruments/guitar/note.rb +0 -24
- data/lib/coltrane_instruments/guitar/string.rb +0 -29
- data/lib/os.rb +0 -21
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'coltrane'
|
4
|
+
require 'coltrane/representation'
|
5
|
+
require 'coltrane/renderers'
|
6
|
+
|
7
|
+
require 'coltrane/commands/command'
|
8
|
+
require 'coltrane/commands/notes'
|
9
|
+
require 'coltrane/commands/chords'
|
10
|
+
require 'coltrane/commands/scale'
|
11
|
+
require 'coltrane/commands/progression'
|
12
|
+
require 'coltrane/commands/common_chords'
|
13
|
+
require 'coltrane/commands/find_scale'
|
14
|
+
require 'coltrane/commands/find_progression'
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Coltrane
|
2
|
+
module Commands
|
3
|
+
class Chords < Command
|
4
|
+
attr_reader :chord, :flavor, :on, :preface
|
5
|
+
|
6
|
+
def initialize(chord = nil,
|
7
|
+
flavor: :notes,
|
8
|
+
on: :text,
|
9
|
+
notes: nil,
|
10
|
+
preface: nil,
|
11
|
+
**options)
|
12
|
+
if chord
|
13
|
+
@chord = chord.is_a?(Theory::Chord) ? chord : Theory::Chord.new(name: chord)
|
14
|
+
elsif notes
|
15
|
+
@chord = Theory::Chord.new(notes: notes&.split('-'))
|
16
|
+
else
|
17
|
+
raise 'Provide chord names or notes. Ex: coltrane chords Cm7-Db7, ' \
|
18
|
+
'or coltrane chords --notes C-E-G'
|
19
|
+
end
|
20
|
+
|
21
|
+
@flavor = flavor.to_sym
|
22
|
+
@preface = preface || @chord.name
|
23
|
+
@on = on.to_sym
|
24
|
+
end
|
25
|
+
|
26
|
+
def representation
|
27
|
+
return on_model if on == :text
|
28
|
+
{ preface => on_model }
|
29
|
+
end
|
30
|
+
|
31
|
+
def on_model
|
32
|
+
case on
|
33
|
+
when :text then chord
|
34
|
+
when :guitar then Representation::Guitar.find_chords(chord).first(6)
|
35
|
+
when :ukulele, :ukelele then Representation::Ukulele.find_chords(chord).first(6)
|
36
|
+
when :bass then Representation::Bass.find_chords(chord).first(6)
|
37
|
+
when :piano then Representation::Piano.find_notes(chord.notes)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def layout_horizontal?
|
42
|
+
[:guitar, :ukulele, :ukelele, :bass, :piano].include?(on)
|
43
|
+
end
|
44
|
+
|
45
|
+
def renderer_options
|
46
|
+
[
|
47
|
+
{ flavor: flavor },
|
48
|
+
(
|
49
|
+
{
|
50
|
+
layout: :horizontal,
|
51
|
+
per_row: 6,
|
52
|
+
} if layout_horizontal?
|
53
|
+
)
|
54
|
+
]
|
55
|
+
.compact
|
56
|
+
.reduce({}, :merge)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.mercenary_init(program)
|
60
|
+
program.command(:chords) do |c|
|
61
|
+
c.alias(:chord)
|
62
|
+
c.syntax 'chords [<chord-name>] [--on <instrument>]'
|
63
|
+
c.description 'Shows the given chord. Ex: coltrane chord Cmaj7 --on piano'
|
64
|
+
c.alias(:chords)
|
65
|
+
c.option :notes, '--notes C-D-E', 'finds chords with those notes, ' \
|
66
|
+
'provided they are separated by dashes'
|
67
|
+
|
68
|
+
add_shared_option(:flavor, c)
|
69
|
+
add_shared_option(:on, c)
|
70
|
+
c.action { |(chords), **options|
|
71
|
+
(chords&.split('-') || [nil]).each { |chord| new(chord, **options).render }
|
72
|
+
}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Coltrane
|
2
|
+
module Commands
|
3
|
+
class Command
|
4
|
+
COMMON_OPTIONS = {
|
5
|
+
on: [
|
6
|
+
'--on guitar INSTRUMENT',
|
7
|
+
'Shows the notes on the given instrument/representation type. ' \
|
8
|
+
'Can be piano, guitar, ukulele, bass or text'
|
9
|
+
],
|
10
|
+
|
11
|
+
flavor: [
|
12
|
+
'--flavor FLAVOR',
|
13
|
+
'Chooses which additional information to display: ' \
|
14
|
+
'marks, notes, intervals or degrees'
|
15
|
+
]
|
16
|
+
}
|
17
|
+
|
18
|
+
def render
|
19
|
+
puts "\n" + Renderers::TextRenderer.render(
|
20
|
+
representation, **renderer_options
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def renderer_options
|
25
|
+
{}
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
|
30
|
+
def subclasses
|
31
|
+
@subclasses ||= []
|
32
|
+
end
|
33
|
+
|
34
|
+
def inherited(base)
|
35
|
+
subclasses << base
|
36
|
+
super(base)
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_shared_option(option_name, mercenary_command)
|
40
|
+
mercenary_command.option(option_name, *COMMON_OPTIONS[option_name])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Coltrane
|
2
|
+
module Commands
|
3
|
+
class CommonChords < Command
|
4
|
+
def self.parse(scale_notation)
|
5
|
+
scale_notation
|
6
|
+
.split(' ', 2)
|
7
|
+
.yield_self { |(tone, scale_name)|
|
8
|
+
Theory::Scale.fetch(scale_name.gsub(' ', '_'), tone)
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.mercenary_init(program)
|
13
|
+
program.command(:'common-chords') do |c|
|
14
|
+
c.alias(:'common-chord')
|
15
|
+
add_shared_option(:flavor, c)
|
16
|
+
add_shared_option(:on, c)
|
17
|
+
c.syntax 'common-chords [TONE_1 SCALE_NAME_1], [TONE_2 SCALE_NAME_2], [...]'
|
18
|
+
c.description 'Finds chords that are shared between the given scales'
|
19
|
+
c.action do |(*scale_strings), **options|
|
20
|
+
scale_strings
|
21
|
+
.join(' ')
|
22
|
+
.split(',')
|
23
|
+
.map { |scale_notation|
|
24
|
+
Commands::Scale.parse(scale_notation).all_chords
|
25
|
+
}
|
26
|
+
.reduce(:&)
|
27
|
+
.each { |chord| Commands::Chords.new(chord, **options).render }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Style/Documentation
|
4
|
+
|
5
|
+
module Coltrane
|
6
|
+
class CommandError < StandardError
|
7
|
+
def initialize(msg)
|
8
|
+
super msg
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class WrongFlavorError < CommandError
|
13
|
+
def initialize(msg = nil)
|
14
|
+
super msg || 'Wrong flavor. Check possible flavors with `coltrane list flavors`.'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class BadFindScales < CommandError
|
19
|
+
def initialize(msg = nil)
|
20
|
+
super msg || 'Provide --notes or --chords. Ex: `coltrane find-scale --notes C-E-G`.'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class WrongRepresentationTypeError < CommandError
|
25
|
+
def initialize(type)
|
26
|
+
super "The provided representation type (#{type}) "\
|
27
|
+
'is not available at the moment.'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class BadScaleError < CommandError
|
32
|
+
def initialize(msg = nil)
|
33
|
+
super msg || 'Incorrect scale, please specify scale and root separated by `-`. Ex: `coltrane scale major-C'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class BadChordError < CommandError
|
38
|
+
def initialize(msg = nil)
|
39
|
+
super msg || 'Incorrect chord, please specify a set of chords separated by `-`. Ex: coltrane chord CM7'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# rubocop:enable Style/Documentation
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Coltrane
|
2
|
+
module Commands
|
3
|
+
class FindProgression < Command
|
4
|
+
attr_reader :progression_set
|
5
|
+
|
6
|
+
def initialize(progression_set, **options)
|
7
|
+
@progression_set = progression_set
|
8
|
+
end
|
9
|
+
|
10
|
+
def representation
|
11
|
+
progression_set
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.mercenary_init(program)
|
15
|
+
program.command(:'find-progression') do |c|
|
16
|
+
c.syntax 'find-progression <list of chords>'
|
17
|
+
c.description 'Find progressions in scales. Ex: coltrane find-progression AM-DM-F#m-EM'
|
18
|
+
c.action do |(chord_notation)|
|
19
|
+
chord_notation
|
20
|
+
.split('-')
|
21
|
+
.yield_self { |chords| Theory::Progression.find(*chords) }
|
22
|
+
.yield_self { |progression_set| new(progression_set).render }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Coltrane
|
2
|
+
module Commands
|
3
|
+
class FindScale < Command
|
4
|
+
attr_reader :scale_set
|
5
|
+
|
6
|
+
def initialize(scale_set)
|
7
|
+
@scale_set = scale_set
|
8
|
+
end
|
9
|
+
|
10
|
+
def representation
|
11
|
+
scale_set
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.mercenary_init(program)
|
15
|
+
program.command(:'find-scale') do |c|
|
16
|
+
c.syntax 'find-scale --notes C-D-E-...] OR --chord Cmaj7-Db7'
|
17
|
+
c.description 'finds scales with the provided --notes or --chord'
|
18
|
+
c.option :notes, '--notes C-D-E', 'Find scales with those notes'
|
19
|
+
c.option :chords, '--chords Cmaj7-D11', 'find scales with those chords'
|
20
|
+
c.action do |(_), notes: nil, chords: nil|
|
21
|
+
begin
|
22
|
+
if notes
|
23
|
+
Theory::Scale.having_notes(
|
24
|
+
Theory::NoteSet[*notes.to_s.split('-')]
|
25
|
+
)
|
26
|
+
elsif chords
|
27
|
+
Theory::Scale.having_chords(*chords.to_s.split('-'))
|
28
|
+
else
|
29
|
+
raise 'Provide --notes or --chords separated by dashes.' \
|
30
|
+
'For example coltrane find-scale --notes C-E-F#'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
.yield_self { |scale_set| new(scale_set).render }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Coltrane
|
2
|
+
module Commands
|
3
|
+
class Notes < Command
|
4
|
+
attr_reader :notes, :flavor, :on, :preface
|
5
|
+
|
6
|
+
def initialize(notes, flavor: :notes, on: :text, preface: nil)
|
7
|
+
raise 'Provide some notes. Ex: coltrane notes C-D-Gb' if notes.nil?
|
8
|
+
@notes = notes.is_a?(Theory::NoteSet) ? notes : Theory::NoteSet[*notes.split('-')]
|
9
|
+
@flavor = flavor.to_sym
|
10
|
+
@preface = preface || 'Here are the notes you asked for'
|
11
|
+
@on = on
|
12
|
+
end
|
13
|
+
|
14
|
+
def representation
|
15
|
+
{ preface => on_model }
|
16
|
+
end
|
17
|
+
|
18
|
+
def renderer_options
|
19
|
+
{ flavor: flavor }
|
20
|
+
end
|
21
|
+
|
22
|
+
def on_model
|
23
|
+
case on.to_sym
|
24
|
+
when :text then notes
|
25
|
+
when :guitar then Representation::Guitar.find_notes(notes)
|
26
|
+
when :ukulele, :ukelele then Representation::Ukulele.find_notes(notes)
|
27
|
+
when :bass then Representation::Bass.find_notes(notes)
|
28
|
+
when :piano then Representation::Piano.find_notes(notes)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.mercenary_init(program)
|
33
|
+
program.command(:notes) do |c|
|
34
|
+
c.alias(:note)
|
35
|
+
c.syntax 'notes <notes separated by space> [--on <instrument>]'
|
36
|
+
c.description 'Shows the given notes.'
|
37
|
+
add_shared_option(:flavor, c)
|
38
|
+
add_shared_option(:on, c)
|
39
|
+
c.action { |(notes), **options| new(notes, **options).render }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Coltrane
|
2
|
+
module Commands
|
3
|
+
class Progression < Command
|
4
|
+
def self.mercenary_init(program)
|
5
|
+
program.command(:progression) do |c|
|
6
|
+
c.syntax 'progression <roman numeral notation> in <key> [--on <instrument>]'
|
7
|
+
c.description 'Gives you chords of a progression in a key. Ex: coltrane progression I-IV-iv-V in Am --on guitar'
|
8
|
+
add_shared_option(:flavor, c)
|
9
|
+
add_shared_option(:on, c)
|
10
|
+
c.action do |(prog, _, key), **options|
|
11
|
+
prog
|
12
|
+
.tr('-', '_')
|
13
|
+
.yield_self { |possible_method|
|
14
|
+
if Theory::Progression.respond_to?(possible_method)
|
15
|
+
Theory::Progression.send(possible_method, key)
|
16
|
+
else
|
17
|
+
Theory::Progression.new(prog, key: key)
|
18
|
+
end
|
19
|
+
}
|
20
|
+
.chords
|
21
|
+
.each { |chord| Commands::Chords.new(chord, **options).render }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
File without changes
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Coltrane
|
2
|
+
module Commands
|
3
|
+
class Scale < Command
|
4
|
+
def representation
|
5
|
+
return on_model if on == :text
|
6
|
+
{ preface => on_model }
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.parse(scale_notation)
|
10
|
+
scale_notation
|
11
|
+
.split(' ', 2)
|
12
|
+
.yield_self { |(tone, scale_name)|
|
13
|
+
Theory::Scale.fetch(scale_name.gsub(' ', '_'), tone)
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.mercenary_init(program)
|
18
|
+
program.command(:scale) do |c|
|
19
|
+
c.syntax 'scale <root_note> <scale name> [--on <instrument>]'
|
20
|
+
c.description 'Gives you information about a scale. Ex: coltrane scale D Natural Minor --on guitar'
|
21
|
+
c.option :tertians, '--tertians SIZE', 'Outputs all tertian chords from the given size from the scale'
|
22
|
+
c.option :chords, '--chords [SIZE]', 'Outputs all chords from given size from the scale. Leave size empty to retrieve all'
|
23
|
+
add_shared_option(:flavor, c)
|
24
|
+
add_shared_option(:on, c)
|
25
|
+
|
26
|
+
c.action { |scale_notation, **options|
|
27
|
+
parse(scale_notation.join(' '))
|
28
|
+
.yield_self { |scale|
|
29
|
+
if options[:tertians]
|
30
|
+
scale
|
31
|
+
.tertians(options[:tertians].to_i)
|
32
|
+
.each { |chord| Commands::Chords.new(chord, **options).render }
|
33
|
+
elsif options[:chords]
|
34
|
+
scale.chords(options[:chords].to_i)
|
35
|
+
.each { |chord| Commands::Chords.new(chord, **options).render }
|
36
|
+
else
|
37
|
+
scale.notes
|
38
|
+
.yield_self {|notes| Commands::Notes.new(notes, **options.merge(preface: scale.full_name)).render }
|
39
|
+
end
|
40
|
+
}
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Coltrane
|
2
|
+
module Renderers
|
3
|
+
module Renderer
|
4
|
+
include Dry::Monads::Try::Mixin
|
5
|
+
|
6
|
+
def render(model, **options)
|
7
|
+
model
|
8
|
+
.yield_self { |model| model_class_list(model) }
|
9
|
+
.yield_self { |model_classes| renderer_class(*model_classes) }
|
10
|
+
.value_or { raise("Renderer doesn't implements #{model.class}") }
|
11
|
+
.new(model, **options)
|
12
|
+
.render
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def model_class_list(model)
|
18
|
+
model
|
19
|
+
.class
|
20
|
+
.ancestors
|
21
|
+
.yield_self { |classes| classes[0...classes.index(Object)] }
|
22
|
+
end
|
23
|
+
|
24
|
+
def renderer_class(*classes)
|
25
|
+
return if classes.empty?
|
26
|
+
Try() { classes }
|
27
|
+
.fmap { |classes|
|
28
|
+
classes
|
29
|
+
.first
|
30
|
+
.to_s
|
31
|
+
.gsub('Coltrane::', '')
|
32
|
+
.gsub('::', '')
|
33
|
+
.prepend("#{self.name}::")
|
34
|
+
.concat('Drawer')
|
35
|
+
.yield_self {|class_name| Object.const_get(class_name) }
|
36
|
+
}
|
37
|
+
.to_maybe
|
38
|
+
.or(renderer_class(*classes[1..-1]))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|