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
data/lib/cli/text.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Coltrane
|
4
|
-
module Cli
|
5
|
-
# A text representation
|
6
|
-
class Text < Representation
|
7
|
-
def render
|
8
|
-
case Cli.config.flavor
|
9
|
-
when :marks, :notes, :degrees then @notes.pretty_names.join(' ')
|
10
|
-
when :intervals then @notes.map { |n| (@notes.first - n).name }.join(' ')
|
11
|
-
else raise WrongFlavorError
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
data/lib/cli/ukulele.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Coltrane
|
4
|
-
module Cli
|
5
|
-
# Renders notes in a common most popular ukulele scheme
|
6
|
-
class Ukulele < Guitar
|
7
|
-
SPECIAL_FRETS = [5, 7, 9, 12].freeze
|
8
|
-
|
9
|
-
def initialize(notes, tuning: %w[G C E A], frets: 12)
|
10
|
-
super
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
data/lib/coltrane/cache.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Coltrane
|
4
|
-
# A simple caching based on serializing objects into files
|
5
|
-
# maybe this should changed to save in a single json file
|
6
|
-
class Cache
|
7
|
-
class << self
|
8
|
-
def find_or_record(key, &block)
|
9
|
-
if @disabled || !(cached = fetch(key))
|
10
|
-
cached = yield block
|
11
|
-
record(key, cached)
|
12
|
-
end
|
13
|
-
cached
|
14
|
-
end
|
15
|
-
|
16
|
-
def disable
|
17
|
-
@disabled = true
|
18
|
-
end
|
19
|
-
|
20
|
-
def enable
|
21
|
-
@disabled = false
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def dir
|
27
|
-
dir = File.expand_path('../../../', __FILE__) + '/cache/'
|
28
|
-
Dir.mkdir(dir) unless Dir.exist?(dir)
|
29
|
-
dir
|
30
|
-
end
|
31
|
-
|
32
|
-
def fetch(key)
|
33
|
-
Marshal.load File.read(dir + key) if File.file?(dir + key)
|
34
|
-
end
|
35
|
-
|
36
|
-
def record(key, contents)
|
37
|
-
File.open(dir + key, 'w') do |f|
|
38
|
-
f.write Marshal.dump(contents)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/lib/coltrane/cadence.rb
DELETED
data/lib/coltrane/chord.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Coltrane
|
4
|
-
# It describe a chord
|
5
|
-
|
6
|
-
class Chord
|
7
|
-
attr_reader :root_note, :quality, :notes
|
8
|
-
include ChordSubstitutions
|
9
|
-
|
10
|
-
def initialize(notes: nil, root_note: nil, quality: nil, name: nil)
|
11
|
-
if notes
|
12
|
-
notes = NoteSet[*notes] if notes.is_a?(Array)
|
13
|
-
@notes = notes
|
14
|
-
@root_note = notes.first
|
15
|
-
@quality = ChordQuality.new(notes: notes)
|
16
|
-
elsif root_note && quality
|
17
|
-
@notes = quality.notes_for(root_note)
|
18
|
-
@root_note = root_note
|
19
|
-
@quality = quality
|
20
|
-
elsif name
|
21
|
-
@root_note, @quality, @notes = parse_from_name(name)
|
22
|
-
else
|
23
|
-
raise WrongKeywordsError,
|
24
|
-
'[notes:] || [root_note:, quality:] || [name:]'
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def name
|
29
|
-
"#{root_note}#{quality}"
|
30
|
-
end
|
31
|
-
|
32
|
-
alias to_s name
|
33
|
-
|
34
|
-
def pretty_name
|
35
|
-
"#{root_note.pretty_name}#{quality.name}"
|
36
|
-
end
|
37
|
-
|
38
|
-
def intervals
|
39
|
-
IntervalSequence.new(NoteSet.new(notes))
|
40
|
-
end
|
41
|
-
|
42
|
-
def size
|
43
|
-
notes.size
|
44
|
-
end
|
45
|
-
|
46
|
-
def scales
|
47
|
-
Scale.having_chord(name)
|
48
|
-
end
|
49
|
-
|
50
|
-
def next_inversion
|
51
|
-
Chord.new(notes: notes.rotate(1))
|
52
|
-
end
|
53
|
-
|
54
|
-
def invert(n = 1)
|
55
|
-
Chord.new(notes: notes.rotate(n))
|
56
|
-
end
|
57
|
-
|
58
|
-
def previous_inversion
|
59
|
-
Chord.new(notes: notes.rotate(-1))
|
60
|
-
end
|
61
|
-
|
62
|
-
def +(other)
|
63
|
-
case other
|
64
|
-
when Note, NoteSet, Interval then Chord.new(notes: notes + other)
|
65
|
-
when Chord then Chord.new(notes: notes + other.notes)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def -(other)
|
70
|
-
case other
|
71
|
-
when Note, NoteSet, Interval, Numeric then Chord.new(notes: notes - other)
|
72
|
-
when Chord then Chord.new(notes: notes - other.notes)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
protected
|
77
|
-
|
78
|
-
def parse_from_name(name)
|
79
|
-
chord_name, bass = name.match?(/\/9/) ? [name, nil] : name.split('/')
|
80
|
-
chord_regex = /([A-Z](?:#|b)?)(.*)/
|
81
|
-
_, root_name, quality_name = chord_name.match(chord_regex).to_a
|
82
|
-
root = Note[root_name]
|
83
|
-
quality = ChordQuality.new(name: quality_name, bass: bass)
|
84
|
-
notes = quality.notes_for(root)
|
85
|
-
notes << Note[bass] unless bass.nil?
|
86
|
-
[root, quality, notes]
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
@@ -1,111 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Coltrane
|
4
|
-
# It describe the quality of a chord, like maj7 or dim.
|
5
|
-
class ChordQuality < IntervalSequence
|
6
|
-
include Qualities
|
7
|
-
attr_reader :name
|
8
|
-
# QUALITIES_FILE = File.expand_path("#{'../' * 3}data/qualities.json", __FILE__)
|
9
|
-
|
10
|
-
private
|
11
|
-
|
12
|
-
def self.chord_trie
|
13
|
-
File.expand_path("#{'../' * 3}data/qualities.json", __FILE__)
|
14
|
-
trie = QUALITIES
|
15
|
-
|
16
|
-
trie.clone_values from_keys: ['Perfect Unison', 'Major Third'],
|
17
|
-
to_keys: ['Perfect Unison', 'Major Second'],
|
18
|
-
suffix: 'sus2'
|
19
|
-
|
20
|
-
trie.clone_values from_keys: ['Perfect Unison', 'Major Third'],
|
21
|
-
to_keys: ['Perfect Unison', 'Perfect Fourth'],
|
22
|
-
suffix: 'sus4'
|
23
|
-
trie.deep_dup
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.intervals_per_name(quality_names: {}, intervals: [], hash: nil)
|
27
|
-
hash ||= chord_trie
|
28
|
-
return quality_names if hash.empty?
|
29
|
-
if hash['name']
|
30
|
-
quality_names[hash.delete('name')] = intervals.map { |n| Interval.public_send(n.underscore) }
|
31
|
-
end
|
32
|
-
hash.reduce(quality_names) do |memo, (interval, values)|
|
33
|
-
memo.merge intervals_per_name(hash: values,
|
34
|
-
quality_names: quality_names,
|
35
|
-
intervals: intervals + [interval])
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
NAMES = intervals_per_name
|
40
|
-
|
41
|
-
def find_chord(given_interval_names, trie: self.class.chord_trie, last_name: nil)
|
42
|
-
return if trie.nil?
|
43
|
-
if given_interval_names.empty?
|
44
|
-
@found = true
|
45
|
-
return trie['name']
|
46
|
-
end
|
47
|
-
interval = given_interval_names.shift
|
48
|
-
new_trie = trie[interval.full_name]
|
49
|
-
find_chord given_interval_names, last_name: (trie['name'] || last_name),
|
50
|
-
trie: new_trie
|
51
|
-
end
|
52
|
-
|
53
|
-
def normal_sequence
|
54
|
-
%i[unison third! fifth sixth! seventh ninth eleventh! thirteenth]
|
55
|
-
end
|
56
|
-
|
57
|
-
def sus2_sequence
|
58
|
-
%i[unison second! fifth sixth! seventh ninth eleventh! thirteenth]
|
59
|
-
end
|
60
|
-
|
61
|
-
def sus4_sequence
|
62
|
-
%i[unison fourth! fifth sixth! seventh ninth eleventh! thirteenth]
|
63
|
-
end
|
64
|
-
|
65
|
-
def retrieve_chord_intervals(chord_sequence = normal_sequence)
|
66
|
-
ints = IntervalSequence.new(*self)
|
67
|
-
chord_sequence.map do |int_sym|
|
68
|
-
next unless interval_name = ints.public_send(int_sym)
|
69
|
-
ints.delete_if { |i| i.cents == IntervalClass.new(interval_name).cents }
|
70
|
-
interval_name
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
public
|
75
|
-
|
76
|
-
def get_name
|
77
|
-
find_chord(retrieve_chord_intervals.compact) ||
|
78
|
-
find_chord(retrieve_chord_intervals(sus2_sequence).compact) ||
|
79
|
-
find_chord(retrieve_chord_intervals(sus4_sequence).compact) ||
|
80
|
-
raise(ChordNotFoundError)
|
81
|
-
end
|
82
|
-
|
83
|
-
def suspension_type
|
84
|
-
if has_major_second?
|
85
|
-
'sus2'
|
86
|
-
else has_fourth?
|
87
|
-
'sus4'
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def initialize(name: nil, notes: nil, bass: nil)
|
92
|
-
if name
|
93
|
-
@name = bass.nil? ? name : [name, bass].join('/')
|
94
|
-
super(*intervals_from_name(name))
|
95
|
-
elsif notes
|
96
|
-
super(notes: notes)
|
97
|
-
@name = get_name
|
98
|
-
else
|
99
|
-
raise WrongKeywordsError, '[name:] || [notes:]'
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
alias to_s name
|
104
|
-
|
105
|
-
private
|
106
|
-
|
107
|
-
def intervals_from_name(name)
|
108
|
-
NAMES[name] || NAMES["M#{name}"] || raise(ChordNotFoundError)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Coltrane
|
4
|
-
class CircleOfFifths
|
5
|
-
attr_reader :notes
|
6
|
-
|
7
|
-
LETTER_SEQUENCE = %w[C G D A E B F].freeze
|
8
|
-
|
9
|
-
def initialize(start_note = Note['C'], size = Float::INFINITY)
|
10
|
-
index = letters.index(start_note.name[0])
|
11
|
-
@notes = fifths(note: start_note - Interval.perfect_fifth,
|
12
|
-
size: size,
|
13
|
-
index: (index - 1) % LETTER_SEQUENCE.size)
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def fifths(note:, index: nil, notes: [], size:)
|
19
|
-
return notes if size == 0
|
20
|
-
return notes if notes.any? && note.as(letters(index)).name == notes.first.name
|
21
|
-
fifths note: note + Interval.perfect_fifth,
|
22
|
-
notes: notes + [note.as(letters(index))],
|
23
|
-
index: index + 1,
|
24
|
-
size: size - 1
|
25
|
-
end
|
26
|
-
|
27
|
-
def letters(i = nil)
|
28
|
-
i.nil? ? LETTER_SEQUENCE : LETTER_SEQUENCE[i % LETTER_SEQUENCE.size]
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,94 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Coltrane
|
4
|
-
# This module deals with well known scales on music
|
5
|
-
module ClassicScales
|
6
|
-
SCALES = {
|
7
|
-
'Pentatonic Major' => [2, 2, 3, 2, 3],
|
8
|
-
'Blues Major' => [2, 1, 1, 3, 2, 3],
|
9
|
-
'Harmonic Minor' => [2, 1, 2, 2, 1, 3, 1],
|
10
|
-
'Hungarian Minor' => [2, 1, 2, 1, 1, 3, 1],
|
11
|
-
'Pentatonic Minor' => [3, 2, 2, 3, 2],
|
12
|
-
'Blues Minor' => [3, 2, 1, 1, 3, 2],
|
13
|
-
'Whole Tone' => [2, 2, 2, 2, 2, 2],
|
14
|
-
'Flamenco' => [1, 3, 1, 2, 1, 2, 2],
|
15
|
-
'Chromatic' => [1] * 12
|
16
|
-
}.freeze
|
17
|
-
|
18
|
-
GREEK_MODES = %w[
|
19
|
-
Ionian
|
20
|
-
Dorian
|
21
|
-
Phrygian
|
22
|
-
Lydian
|
23
|
-
Mixolydian
|
24
|
-
Aeolian
|
25
|
-
Locrian
|
26
|
-
].freeze
|
27
|
-
|
28
|
-
# Creates factories for scales
|
29
|
-
SCALES.each do |name, distances|
|
30
|
-
define_method name.underscore do |tone = 'C', mode = 1|
|
31
|
-
new(*distances, tone: tone, mode: mode, name: name)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# Creates factories for Greek Modes
|
36
|
-
GREEK_MODES.each_with_index do |mode, index|
|
37
|
-
mode_name = mode
|
38
|
-
mode_n = index + 1
|
39
|
-
define_method mode.underscore do |tone = 'C'|
|
40
|
-
new(notes: DiatonicScale.new(tone).notes.rotate(index))
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# Factories for the diatonic scale
|
45
|
-
def major(note = 'C')
|
46
|
-
DiatonicScale.new(note)
|
47
|
-
end
|
48
|
-
|
49
|
-
def minor(note = 'A')
|
50
|
-
DiatonicScale.new(note, major: false)
|
51
|
-
end
|
52
|
-
|
53
|
-
alias diatonic major
|
54
|
-
alias natural_minor minor
|
55
|
-
alias pentatonic pentatonic_major
|
56
|
-
alias blues blues_major
|
57
|
-
|
58
|
-
def known_scales
|
59
|
-
SCALES.keys + ['Major', 'Natural Minor']
|
60
|
-
end
|
61
|
-
|
62
|
-
# List of scales appropriate for search
|
63
|
-
def standard_scales
|
64
|
-
known_scales - ['Chromatic']
|
65
|
-
end
|
66
|
-
|
67
|
-
def fetch(name, tone = nil)
|
68
|
-
Coltrane::Scale.public_send(name, tone)
|
69
|
-
end
|
70
|
-
|
71
|
-
def having_notes(notes)
|
72
|
-
format = { scales: [], results: {} }
|
73
|
-
standard_scales.each_with_object(format) do |name, output|
|
74
|
-
PitchClass.all.each.map do |tone|
|
75
|
-
scale = send(name.underscore, tone)
|
76
|
-
output[:results][name] ||= {}
|
77
|
-
next if output[:results][name].key?(tone.integer)
|
78
|
-
output[:scales] << scale if scale.include?(notes)
|
79
|
-
output[:results][name][tone.integer] = scale.notes & notes
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def having_chords(*chords)
|
85
|
-
should_create = !chords.first.is_a?(Chord)
|
86
|
-
notes = chords.reduce(NoteSet[]) do |memo, c|
|
87
|
-
memo + (should_create ? Chord.new(name: c) : c).notes
|
88
|
-
end
|
89
|
-
having_notes(notes)
|
90
|
-
end
|
91
|
-
|
92
|
-
alias having_chord having_chords
|
93
|
-
end
|
94
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Coltrane
|
4
|
-
class DiatonicScale < Scale
|
5
|
-
def initialize(tone, major: true)
|
6
|
-
@major = major
|
7
|
-
tone = Note[tone]
|
8
|
-
notes = CircleOfFifths.new(tone - (major? ? 0 : 9), 7).notes.sort
|
9
|
-
super notes: notes.rotate(notes.index(tone))
|
10
|
-
end
|
11
|
-
|
12
|
-
def name
|
13
|
-
major? ? 'Major' : 'Natural Minor'
|
14
|
-
end
|
15
|
-
|
16
|
-
def relative_minor
|
17
|
-
minor? ? self : self.class.new(@tone + 9, major: false)
|
18
|
-
end
|
19
|
-
|
20
|
-
def relative_major
|
21
|
-
major? ? self : self.class.new(@tone - 9, major: true)
|
22
|
-
end
|
23
|
-
|
24
|
-
def relative
|
25
|
-
major? ? relative_minor : relative_major
|
26
|
-
end
|
27
|
-
|
28
|
-
def major?
|
29
|
-
!!@major
|
30
|
-
end
|
31
|
-
|
32
|
-
def minor?
|
33
|
-
!@major
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|