coltrane 1.0.2 → 1.0.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +2 -5
- data/Gemfile.lock +3 -3
- data/coltrane.gemspec +1 -1
- data/db/schema.rb +30 -0
- data/exe/coltrane +21 -27
- data/lib/cli/bass_guitar.rb +1 -4
- data/lib/cli/chord.rb +3 -10
- data/lib/cli/errors.rb +4 -10
- data/lib/cli/guitar.rb +10 -12
- data/lib/cli/notes.rb +4 -7
- data/lib/cli/piano.rb +8 -11
- data/lib/cli/representation.rb +14 -14
- data/lib/cli/scale.rb +11 -15
- data/lib/cli/text.rb +3 -6
- data/lib/cli/ukulele.rb +2 -5
- data/lib/{cli.rb → coltrane-cli.rb} +2 -4
- data/lib/coltrane.rb +1 -4
- data/lib/coltrane/cache.rb +9 -10
- data/lib/coltrane/cadence.rb +1 -3
- data/lib/coltrane/chord.rb +8 -16
- data/lib/coltrane/chord_cache.rb +4 -0
- data/lib/coltrane/chord_quality.rb +8 -7
- data/lib/coltrane/classic_progressions.rb +7 -10
- data/lib/coltrane/classic_scales.rb +43 -30
- data/lib/coltrane/errors.rb +10 -17
- data/lib/coltrane/interval.rb +23 -24
- data/lib/coltrane/interval_sequence.rb +7 -8
- data/lib/coltrane/interval_set.rb +0 -1
- data/lib/coltrane/note.rb +46 -23
- data/lib/coltrane/note_set.rb +14 -12
- data/lib/coltrane/pitch.rb +4 -5
- data/lib/coltrane/progression.rb +20 -9
- data/lib/coltrane/qualities.rb +112 -114
- data/lib/coltrane/roman_chord.rb +5 -8
- data/lib/coltrane/scale.rb +33 -25
- data/lib/coltrane/scale_chord.rb +4 -0
- data/lib/coltrane/version.rb +1 -3
- data/lib/core_ext.rb +4 -7
- metadata +10 -7
- data/.rubocop.yml +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 34a17f27f9596847f849a499afada6f8bf46a30b712dc7d9eb0cddb92719eb72
|
4
|
+
data.tar.gz: a18d20bcc0a16271fcbcd219d1d10413153ddedabbcf3ae777614847cd2bfd28
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a025c18f84efa7e2a486b02ba9cd94d831ed0334d9ff7a729cdbd22c1b6893a1f79fdfb6f4013e5f1425740734099ce4c13305bcfa5ab0bcbcedb5b236c6c74
|
7
|
+
data.tar.gz: 06a8754da3e82b9da85ee121ed1a71d5c8efbc033fbfb58f1df73dcfa23e03fa218ece40a92d03c9bedfe2997f6ca5de2462a82af096bbb809dc5f06869ba364
|
data/Gemfile
CHANGED
@@ -2,14 +2,11 @@
|
|
2
2
|
|
3
3
|
source 'https://rubygems.org'
|
4
4
|
|
5
|
-
group :test
|
5
|
+
group :test do
|
6
|
+
gem 'rspec'
|
6
7
|
gem 'pry'
|
7
8
|
gem 'pry-byebug'
|
8
9
|
gem 'pry-rescue'
|
9
|
-
end
|
10
|
-
|
11
|
-
group :test do
|
12
|
-
gem 'rspec'
|
13
10
|
gem 'simplecov', require: false
|
14
11
|
gem 'rubocop', require: false
|
15
12
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
coltrane (1.0.
|
5
|
-
|
4
|
+
coltrane (1.0.1)
|
5
|
+
chroma (~> 0.2.0)
|
6
6
|
facets (~> 3.1)
|
7
7
|
mercenary (~> 0.3)
|
8
8
|
paint (~> 2.0)
|
@@ -12,8 +12,8 @@ GEM
|
|
12
12
|
specs:
|
13
13
|
ast (2.3.0)
|
14
14
|
byebug (9.1.0)
|
15
|
+
chroma (0.2.0)
|
15
16
|
coderay (1.1.2)
|
16
|
-
color (1.8)
|
17
17
|
diff-lcs (1.3)
|
18
18
|
docile (1.1.5)
|
19
19
|
facets (3.1.0)
|
data/coltrane.gemspec
CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
|
|
32
32
|
|
33
33
|
spec.add_runtime_dependency 'facets', '~> 3.1'
|
34
34
|
spec.add_runtime_dependency 'paint', '~> 2.0'
|
35
|
-
spec.add_runtime_dependency '
|
35
|
+
spec.add_runtime_dependency 'chroma', '~> 0.2.0'
|
36
36
|
spec.add_runtime_dependency 'mercenary', '~> 0.3'
|
37
37
|
spec.add_development_dependency "bundler", '~> 1.14'
|
38
38
|
spec.add_development_dependency "rake", '~> 10.0'
|
data/db/schema.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# This file is auto-generated from the current state of the database. Instead
|
2
|
+
# of editing this file, please use the migrations feature of Active Record to
|
3
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
4
|
+
#
|
5
|
+
# Note that this schema.rb definition is the authoritative source for your
|
6
|
+
# database schema. If you need to create the application database on another
|
7
|
+
# system, you should be using db:schema:load, not running all the migrations
|
8
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
9
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
10
|
+
#
|
11
|
+
# It's strongly recommended that you check this file into your version control system.
|
12
|
+
|
13
|
+
ActiveRecord::Schema.define(version: 20170508162849) do
|
14
|
+
|
15
|
+
create_table "scale_caches", force: :cascade do |t|
|
16
|
+
t.string "interval_sequence"
|
17
|
+
t.string "tone"
|
18
|
+
end
|
19
|
+
|
20
|
+
create_table "chord_caches", force: :cascade do |t|
|
21
|
+
t.string "name"
|
22
|
+
t.integer "size"
|
23
|
+
end
|
24
|
+
|
25
|
+
create_table "scale_chords", force: :cascade do |t|
|
26
|
+
t.integer "scale_cache_id"
|
27
|
+
t.integer "chord_cache_id"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/exe/coltrane
CHANGED
@@ -1,13 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
# rubocop:disable Metrics/BlockLength
|
5
2
|
|
6
3
|
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
7
4
|
|
8
5
|
require 'core_ext'
|
9
6
|
require 'coltrane'
|
10
|
-
require 'cli'
|
7
|
+
require 'coltrane-cli'
|
11
8
|
|
12
9
|
full_color_terminals = %w[iTerm.app]
|
13
10
|
safe_mode_terminals = %w[Unsupported]
|
@@ -74,9 +71,9 @@ Mercenary.program(:Coltrane) do |p|
|
|
74
71
|
c.option :pentads, '--pentads', 'Outputs pentad chords from the scale'
|
75
72
|
c.option :tertians, '--tertians SIZE', 'Outputs all tertian chords from the given size from the scale'
|
76
73
|
c.option :chords, '--chords [SIZE]', 'Outputs all chords from given size from the scale. Leave size empty to retrieve all'
|
77
|
-
c.action do |(scale_str), flavor:
|
74
|
+
c.action do |(scale_str), flavor:'degrees', on:'text', **options|
|
78
75
|
scale = Coltrane::Cli::Scale.parse(scale_str)
|
79
|
-
keyword_args = {
|
76
|
+
keyword_args = {flavor: flavor, on: on }
|
80
77
|
if options.include?(:triads)
|
81
78
|
chords = scale.triads
|
82
79
|
Coltrane::Cli::Chord.new(*chords, **keyword_args)
|
@@ -90,11 +87,11 @@ Mercenary.program(:Coltrane) do |p|
|
|
90
87
|
chords = scale.tertians(options[:tertians].to_i)
|
91
88
|
Coltrane::Cli::Chord.new(*chords, **keyword_args)
|
92
89
|
elsif options.include?(:chords)
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
90
|
+
if options[:chords].nil?
|
91
|
+
chords = scale.all_chords
|
92
|
+
else
|
93
|
+
chords = scale.chords(options[:chords])
|
94
|
+
end
|
98
95
|
Coltrane::Cli::Chord.new(*chords, **keyword_args)
|
99
96
|
else
|
100
97
|
Coltrane::Cli::Scale.new(scale, **keyword_args)
|
@@ -107,11 +104,11 @@ Mercenary.program(:Coltrane) do |p|
|
|
107
104
|
list.description 'List information.'
|
108
105
|
list.action do |(arg)|
|
109
106
|
puts case arg
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
107
|
+
when 'scales' then Coltrane::Scale.known_scales
|
108
|
+
when 'flavors' then %w[marks notes intervals degrees]
|
109
|
+
when 'instruments' then %w[guitar bass ukulele piano text]
|
110
|
+
when 'chords', 'chord-qualities' then Coltrane::Qualities::CHORD_QUALITIES.keys.sort.join(' ')
|
111
|
+
end
|
115
112
|
end
|
116
113
|
end
|
117
114
|
|
@@ -120,9 +117,9 @@ Mercenary.program(:Coltrane) do |p|
|
|
120
117
|
c.description 'finds scales with the provided --notes or --chord'
|
121
118
|
c.option :notes, '--notes C-D-E', 'Find scales with those notes'
|
122
119
|
c.option :chords, '--chords Cmaj7-D11', 'find scales with those chords'
|
123
|
-
c.action do |(
|
124
|
-
options[:notes] =
|
125
|
-
options[:chords] =
|
120
|
+
c.action do |(arg), options|
|
121
|
+
options[:notes] = "#{options[:notes]}".split('-')
|
122
|
+
options[:chords] = "#{options[:chords]}".split('-')
|
126
123
|
Coltrane::Cli::Scale.find(**options)
|
127
124
|
end
|
128
125
|
end
|
@@ -148,15 +145,14 @@ Mercenary.program(:Coltrane) do |p|
|
|
148
145
|
p.command(:help) do |c|
|
149
146
|
c.description 'May give you some help.'
|
150
147
|
c.syntax 'help <command> [subcommand, sub-subcommand, ...]'
|
151
|
-
c.action do |(*command_path),
|
148
|
+
c.action do |(*command_path), options|
|
152
149
|
if command_path.empty?
|
153
150
|
puts p
|
151
|
+
return
|
154
152
|
else
|
155
|
-
puts
|
156
|
-
|
157
|
-
|
158
|
-
end || "\n Sorry, command found."
|
159
|
-
end
|
153
|
+
puts (command_path.reduce(p) do |memo, key|
|
154
|
+
memo.commands.delete(key.to_sym)
|
155
|
+
end || "\n Sorry, command found.")
|
160
156
|
end
|
161
157
|
end
|
162
158
|
end
|
@@ -170,5 +166,3 @@ Mercenary.program(:Coltrane) do |p|
|
|
170
166
|
|
171
167
|
p.default_command(:about)
|
172
168
|
end
|
173
|
-
|
174
|
-
# rubocop:enable Metrics/BlockLength
|
data/lib/cli/bass_guitar.rb
CHANGED
data/lib/cli/chord.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Coltrane
|
4
2
|
module Cli
|
5
|
-
# Interfaces chord functionality with the lib
|
6
3
|
class Chord
|
7
4
|
def initialize(*chords, on: :text, flavor: 'intervals', notes: nil)
|
8
5
|
@chords =
|
@@ -13,19 +10,15 @@ module Coltrane
|
|
13
10
|
chords
|
14
11
|
end
|
15
12
|
elsif !notes.nil?
|
16
|
-
|
13
|
+
[Coltrane::Chord.new(notes: notes)]
|
17
14
|
end
|
18
15
|
|
19
16
|
@chords.each do |chord|
|
20
17
|
raise ChordNotFoundError unless chord.named?
|
21
18
|
desc = "#{chord.name} chord:"
|
22
|
-
Coltrane::Cli::Notes.new
|
23
|
-
desc: desc,
|
24
|
-
flavor: flavor
|
19
|
+
Coltrane::Cli::Notes.new(chord.notes, on: on, desc: desc, flavor: flavor)
|
25
20
|
end
|
26
21
|
end
|
27
22
|
end
|
28
23
|
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# rubocop:enable Metrics/MethodLength
|
24
|
+
end
|
data/lib/cli/errors.rb
CHANGED
@@ -1,7 +1,3 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# rubocop:disable Style/Documentation
|
4
|
-
|
5
1
|
module Coltrane
|
6
2
|
module Cli
|
7
3
|
class ColtraneCliError < StandardError
|
@@ -11,13 +7,13 @@ module Coltrane
|
|
11
7
|
end
|
12
8
|
|
13
9
|
class WrongFlavorError < ColtraneCliError
|
14
|
-
def initialize(msg
|
10
|
+
def initialize(msg=nil)
|
15
11
|
super msg || 'Wrong flavor. Check possible flavors with `coltrane list flavors`.'
|
16
12
|
end
|
17
13
|
end
|
18
14
|
|
19
15
|
class BadFindScales < ColtraneCliError
|
20
|
-
def initialize(msg
|
16
|
+
def initialize(msg=nil)
|
21
17
|
super msg || 'Provide --notes or --chords. Ex: `coltrane find-scale --notes C E G`.'
|
22
18
|
end
|
23
19
|
end
|
@@ -25,10 +21,8 @@ module Coltrane
|
|
25
21
|
class WrongRepresentationTypeError < ColtraneCliError
|
26
22
|
def initialize(type)
|
27
23
|
super "The provided representation type (#{type}) "\
|
28
|
-
|
24
|
+
"is not available at the moment."
|
29
25
|
end
|
30
26
|
end
|
31
27
|
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# rubocop:enable Style/Documentation
|
28
|
+
end
|
data/lib/cli/guitar.rb
CHANGED
@@ -1,10 +1,7 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Coltrane
|
4
2
|
module Cli
|
5
|
-
SPECIAL_FRETS = [3, 5, 7, 9, 12, 15, 17, 19]
|
3
|
+
SPECIAL_FRETS = [3, 5, 7, 9, 12, 15, 17, 19]
|
6
4
|
|
7
|
-
# Renders notes in a common most popular ukulele scheme
|
8
5
|
class Guitar < Representation
|
9
6
|
def initialize(notes, flavor, tuning: %w[E A D G B E], frets: 22)
|
10
7
|
@notes = notes
|
@@ -15,33 +12,34 @@ module Coltrane
|
|
15
12
|
end
|
16
13
|
|
17
14
|
def render
|
18
|
-
[render_notes, render_special_frets, hint].join("\n"
|
15
|
+
[render_notes, render_special_frets, hint].join("\n"*2)
|
19
16
|
end
|
20
17
|
|
21
18
|
def render_notes
|
22
19
|
@tuning.map do |string|
|
23
20
|
string_note = Note[string]
|
24
|
-
|
21
|
+
(@frets+2).times.map do |i|
|
25
22
|
if i.zero?
|
26
23
|
string
|
27
24
|
else
|
28
25
|
fret = i - 1
|
29
26
|
note = string_note + fret
|
30
|
-
m = (@notes.include?(note) ? place_mark(note) :
|
31
|
-
fret.zero? ? (m +
|
27
|
+
m = (@notes.include?(note) ? place_mark(note) : "--")
|
28
|
+
fret.zero? ? (m + " |") : m
|
32
29
|
end
|
33
30
|
end.join(' ')
|
34
31
|
end.join("\n")
|
35
32
|
end
|
36
33
|
|
37
34
|
def render_special_frets
|
38
|
-
|
35
|
+
(@frets+1).times.map do |fret|
|
39
36
|
m = SPECIAL_FRETS.include?(fret) ? fret.to_s.rjust(2, 0.to_s) : ' '
|
40
37
|
"#{m}#{' ' if fret.zero?}"
|
41
38
|
end.join(' ')
|
42
39
|
end
|
43
40
|
|
44
|
-
def render_dotted_frets
|
41
|
+
def render_dotted_frets
|
42
|
+
end
|
45
43
|
|
46
44
|
def place_mark(note)
|
47
45
|
case @flavor
|
@@ -49,9 +47,9 @@ module Coltrane
|
|
49
47
|
when :intervals then (@ref_note - note).name.ljust(2, '-')
|
50
48
|
when :degrees then @notes.degree(note).to_s.rjust(2, '0')
|
51
49
|
when :marks then '◼◼'
|
52
|
-
else raise WrongFlavorError
|
50
|
+
else raise WrongFlavorError.new
|
53
51
|
end
|
54
52
|
end
|
55
53
|
end
|
56
54
|
end
|
57
|
-
end
|
55
|
+
end
|
data/lib/cli/notes.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Coltrane
|
4
2
|
module Cli
|
5
|
-
# Interfaces notes outputting functionality with the lib
|
6
3
|
class Notes
|
7
|
-
def initialize(notes, on: 'text', desc:
|
8
|
-
@desc = desc
|
4
|
+
def initialize(notes, on: 'text', desc: 'The notes you supplied:', flavor: 'notes')
|
5
|
+
@desc = desc
|
9
6
|
flavor = flavor.underscore.to_sym
|
10
7
|
on = on.to_sym
|
11
8
|
notes = Coltrane::NoteSet.new(notes)
|
@@ -14,8 +11,8 @@ module Coltrane
|
|
14
11
|
end
|
15
12
|
|
16
13
|
def render
|
17
|
-
puts "\n"
|
14
|
+
puts "\n"+[@desc, @representation.render].join("\n"*2)
|
18
15
|
end
|
19
16
|
end
|
20
17
|
end
|
21
|
-
end
|
18
|
+
end
|
data/lib/cli/piano.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Coltrane
|
4
2
|
module Cli
|
5
|
-
# It allows rendering notes in an ASCII piano
|
6
3
|
class Piano < Representation
|
7
4
|
PIANO_TEMPLATE = <<~ASCII
|
8
5
|
┌─┬─┬┬─┬─╥─┬─┬┬─┬┬─┬─╥─┬─┬┬─┬─╥─┬─┬┬─┬┬─┬─┐
|
@@ -27,11 +24,11 @@ module Coltrane
|
|
27
24
|
|
28
25
|
private
|
29
26
|
|
30
|
-
def replace_x(line, notes, size, index
|
31
|
-
line.gsub('X'
|
32
|
-
note = notes[i
|
33
|
-
next ' '
|
34
|
-
Paint[replacer(note)[size == 2 ? 0..2 : index], 'red']
|
27
|
+
def replace_x(line, notes, size, index=0)
|
28
|
+
line.gsub('X'*size).with_index do |match, i|
|
29
|
+
note = notes[i%notes.size]
|
30
|
+
next ' '*size unless @notes.include?(note)
|
31
|
+
Paint[replacer(note)[size == 2 ? 0..2 : index ], 'red']
|
35
32
|
end
|
36
33
|
end
|
37
34
|
|
@@ -40,7 +37,7 @@ module Coltrane
|
|
40
37
|
case @flavor
|
41
38
|
when :intervals then (@ref_note - note).name
|
42
39
|
when :marks then '◼ '
|
43
|
-
when :degrees then @notes.degree(note).to_s.rjust(2,
|
40
|
+
when :degrees then @notes.degree(note).to_s.rjust(2,'0')
|
44
41
|
when :notes then note.pretty_name.to_s.ljust(2, "\u266E")
|
45
42
|
end
|
46
43
|
end
|
@@ -50,8 +47,8 @@ module Coltrane
|
|
50
47
|
end
|
51
48
|
|
52
49
|
def black_notes
|
53
|
-
Coltrane::Scale.pentatonic_major('C#',
|
50
|
+
Coltrane::Scale.pentatonic_major('C#',4).notes
|
54
51
|
end
|
55
52
|
end
|
56
53
|
end
|
57
|
-
end
|
54
|
+
end
|
data/lib/cli/representation.rb
CHANGED
@@ -1,10 +1,7 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Coltrane
|
4
2
|
module Cli
|
5
|
-
# It manages notes representations, most of times instruments
|
6
3
|
class Representation
|
7
|
-
ACCEPTED_FLAVORS = %i[marks notes intervals degrees]
|
4
|
+
ACCEPTED_FLAVORS = %i[marks notes intervals degrees]
|
8
5
|
|
9
6
|
def self.inherited(subclass)
|
10
7
|
@@types ||= {}
|
@@ -12,15 +9,18 @@ module Coltrane
|
|
12
9
|
end
|
13
10
|
|
14
11
|
def self.build(type, notes, flavor)
|
15
|
-
raise WrongFlavorError unless ACCEPTED_FLAVORS.include?(flavor)
|
12
|
+
raise WrongFlavorError.new unless ACCEPTED_FLAVORS.include?(flavor)
|
16
13
|
type = case type
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
when :ukelele then :ukulele
|
15
|
+
when :bass then :bass_guitar
|
16
|
+
else type
|
17
|
+
end
|
21
18
|
|
22
|
-
|
23
|
-
|
19
|
+
if (the_class = @@types[type])
|
20
|
+
the_class.new(notes, flavor)
|
21
|
+
else
|
22
|
+
raise WrongRepresentationTypeError.new(type)
|
23
|
+
end
|
24
24
|
end
|
25
25
|
|
26
26
|
def initialize(notes, flavor)
|
@@ -31,7 +31,7 @@ module Coltrane
|
|
31
31
|
|
32
32
|
def hint
|
33
33
|
case @flavor
|
34
|
-
when :marks then
|
34
|
+
when :marks then ""
|
35
35
|
when :notes then "(\u266E means the note is natural, not flat nor sharp)"
|
36
36
|
when :intervals
|
37
37
|
<<~DESC
|
@@ -39,9 +39,9 @@ module Coltrane
|
|
39
39
|
Ex: 1P = Perfect First / 3m = Minor Third / 4A = Augmented Fourth
|
40
40
|
DESC
|
41
41
|
|
42
|
-
when :degrees then
|
42
|
+
when :degrees then "(The numbers represent the degree of the note in the scale)"
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
47
|
-
end
|
47
|
+
end
|