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