coltrane 2.1.5 → 2.2.1
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 +17 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +1 -2
- data/Gemfile.lock +9 -21
- data/README.md +4 -2
- data/bin/console +1 -1
- data/coltrane.gemspec +1 -1
- data/lib/cli.rb +1 -1
- data/lib/cli/chord.rb +1 -1
- data/lib/cli/config.rb +4 -3
- data/lib/cli/guitar_chords.rb +31 -31
- data/lib/cli/scale.rb +1 -1
- data/lib/coltrane.rb +4 -3
- data/lib/coltrane/chord_quality.rb +4 -4
- data/lib/coltrane/circle_of_fifths.rb +4 -2
- data/lib/coltrane/classic_scales.rb +2 -2
- data/lib/coltrane/diatonic_scale.rb +3 -1
- data/lib/coltrane/frequency.rb +1 -1
- data/lib/coltrane/frequency_interval.rb +81 -0
- data/lib/coltrane/interval.rb +177 -33
- data/lib/coltrane/interval_class.rb +147 -49
- data/lib/coltrane/interval_sequence.rb +53 -54
- data/lib/coltrane/key.rb +3 -1
- data/lib/coltrane/notable_progressions.rb +0 -1
- data/lib/coltrane/note.rb +4 -10
- data/lib/coltrane/note_set.rb +2 -2
- data/lib/coltrane/pitch_class.rb +24 -2
- data/lib/coltrane/qualities.rb +171 -169
- data/lib/coltrane/scale.rb +22 -15
- data/lib/coltrane/version.rb +1 -1
- data/lib/coltrane/voicing.rb +3 -2
- data/lib/coltrane_game/question.rb +4 -3
- data/lib/coltrane_instruments/guitar.rb +1 -1
- data/lib/coltrane_instruments/guitar/base.rb +1 -1
- data/lib/coltrane_instruments/guitar/chord.rb +18 -16
- data/lib/coltrane_synth.rb +3 -1
- data/lib/coltrane_synth/base.rb +9 -7
- data/lib/coltrane_synth/synth.rb +3 -1
- data/lib/core_ext.rb +1 -30
- data/lib/os.rb +4 -2
- metadata +19 -3
data/lib/coltrane/scale.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Coltrane
|
4
5
|
# Musical scale creation and manipulation
|
@@ -10,19 +11,25 @@ module Coltrane
|
|
10
11
|
|
11
12
|
attr_reader :interval_sequence, :tone
|
12
13
|
|
13
|
-
def initialize(*
|
14
|
+
def initialize(*relative_intervals, tone: 'C',
|
15
|
+
mode: 1,
|
16
|
+
name: nil,
|
17
|
+
notes: nil)
|
14
18
|
@name = name
|
15
|
-
if
|
19
|
+
if relative_intervals.any? && tone
|
16
20
|
@tone = Note[tone]
|
17
|
-
|
18
|
-
@interval_sequence = IntervalSequence.new(
|
21
|
+
relative_intervals = relative_intervals.rotate(mode - 1)
|
22
|
+
@interval_sequence = IntervalSequence.new(
|
23
|
+
relative_intervals: relative_intervals
|
24
|
+
)
|
19
25
|
elsif notes
|
20
26
|
@notes = NoteSet[*notes]
|
21
27
|
@tone = @notes.first
|
22
|
-
ds = @notes.interval_sequence.
|
23
|
-
@interval_sequence = IntervalSequence.new(
|
28
|
+
ds = @notes.interval_sequence.relative_intervals
|
29
|
+
@interval_sequence = IntervalSequence.new(relative_intervals: ds)
|
24
30
|
else
|
25
|
-
raise WrongKeywordsError,
|
31
|
+
raise WrongKeywordsError,
|
32
|
+
'[*relative_intervals, tone: "C", mode: 1] || [notes:]'
|
26
33
|
end
|
27
34
|
end
|
28
35
|
|
@@ -32,7 +39,7 @@ module Coltrane
|
|
32
39
|
|
33
40
|
def name
|
34
41
|
@name = begin
|
35
|
-
is = interval_sequence.
|
42
|
+
is = interval_sequence.relative_intervals
|
36
43
|
(0...is.size).each do |i|
|
37
44
|
if (scale_name = Coltrane::ClassicScales::SCALES.key(is.rotate(i)))
|
38
45
|
return scale_name
|
@@ -132,13 +139,13 @@ module Coltrane
|
|
132
139
|
next memo1 unless size.include?(qintervals.size)
|
133
140
|
memo1 + scale_rotations.each_with_index
|
134
141
|
.reduce([]) do |memo2, (rot, index)|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
+
if (rot & qintervals).size == qintervals.size
|
143
|
+
memo2 + [Chord.new(root_note: degree(index + 1),
|
144
|
+
quality: ChordQuality.new(name: qname))]
|
145
|
+
else
|
146
|
+
memo2
|
147
|
+
end
|
148
|
+
end
|
142
149
|
end
|
143
150
|
end
|
144
151
|
|
data/lib/coltrane/version.rb
CHANGED
data/lib/coltrane/voicing.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module Coltrane
|
3
4
|
# This class describes an actual implementation of a Chord, being aware
|
4
5
|
# of exact octaves of each pitch and even repeating pitches across octaves.
|
5
6
|
class Voicing
|
@@ -35,4 +36,4 @@ module Coltrane
|
|
35
36
|
pitches.map(&:frequency)
|
36
37
|
end
|
37
38
|
end
|
38
|
-
end
|
39
|
+
end
|
@@ -27,23 +27,23 @@ module ColtraneInstruments
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def <=>(other)
|
30
|
-
|
30
|
+
rank <=> other.rank
|
31
31
|
end
|
32
32
|
|
33
33
|
def rank
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
+completeness * 10_000 +
|
35
|
+
+fullness * 1000 +
|
36
|
+
-spreadness * 100 +
|
37
|
+
+easyness * 1
|
38
38
|
end
|
39
39
|
|
40
40
|
def analysis
|
41
41
|
{
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
completeness: completeness,
|
43
|
+
fullness: fullness,
|
44
|
+
easyness: easyness,
|
45
|
+
spreadness: spreadness
|
46
|
+
}
|
47
47
|
end
|
48
48
|
|
49
49
|
def spreadness
|
@@ -70,13 +70,13 @@ module ColtraneInstruments
|
|
70
70
|
return [self] if guitar_notes.size >= guitar.strings.size
|
71
71
|
possible_new_notes(notes_available.positive?).reduce([]) do |memo, n|
|
72
72
|
barre = n.fret if guitar_notes.last == n.fret
|
73
|
-
fingers_change =
|
73
|
+
fingers_change = n.fret == barre || n.fret.zero? ? 0 : 1
|
74
74
|
next memo if (free_fingers - fingers_change).negative?
|
75
75
|
Chord.new(target_chord, guitar_notes: guitar_notes + [n],
|
76
76
|
free_fingers: free_fingers - fingers_change,
|
77
77
|
guitar: guitar,
|
78
78
|
barre: barre)
|
79
|
-
|
79
|
+
.fetch_descendant_chords + memo
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
@@ -89,12 +89,14 @@ module ColtraneInstruments
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def notes_left
|
92
|
-
@notes_left ||=
|
92
|
+
@notes_left ||= begin
|
93
|
+
target_chord.notes - Coltrane::NoteSet[
|
93
94
|
*guitar_notes.map do |n|
|
94
95
|
next if n.pitch.nil?
|
95
96
|
n.pitch.pitch_class
|
96
97
|
end
|
97
|
-
]
|
98
|
+
]
|
99
|
+
end
|
98
100
|
end
|
99
101
|
|
100
102
|
def target_notes
|
@@ -110,7 +112,7 @@ module ColtraneInstruments
|
|
110
112
|
end
|
111
113
|
|
112
114
|
def non_zero_frets
|
113
|
-
frets.reject {|f| f.nil? || f.zero? }
|
115
|
+
frets.reject { |f| f.nil? || f.zero? }
|
114
116
|
end
|
115
117
|
|
116
118
|
def lowest_fret
|
@@ -139,7 +141,7 @@ module ColtraneInstruments
|
|
139
141
|
|
140
142
|
def fret_expansion_range
|
141
143
|
(lowest_possible_fret..highest_possible_fret).to_a +
|
142
|
-
|
144
|
+
[(0 unless barre?)].compact
|
143
145
|
end
|
144
146
|
|
145
147
|
def to_s
|
data/lib/coltrane_synth.rb
CHANGED
data/lib/coltrane_synth/base.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ColtraneSynth
|
2
4
|
class Base
|
3
5
|
attr_reader :device, :buffer
|
4
6
|
|
5
|
-
SAMPLE_RATE =
|
7
|
+
SAMPLE_RATE = 44_000
|
6
8
|
|
7
|
-
def self.play(something, duration=1.0)
|
9
|
+
def self.play(something, duration = 1.0)
|
8
10
|
new.play(*extract_frequencies(something), duration: duration)
|
9
11
|
end
|
10
12
|
|
@@ -17,8 +19,8 @@ module ColtraneSynth
|
|
17
19
|
buffer = @device.output_loop(SAMPLE_RATE)
|
18
20
|
|
19
21
|
SAMPLE_RATE.times do |i|
|
20
|
-
sound = freqs.reduce(0) { |sum, freq| Math.sin(phase(freq)*i) + sum }
|
21
|
-
buffer[i] = (sound * (0x6AFF/freqs.size)).round
|
22
|
+
sound = freqs.reduce(0) { |sum, freq| Math.sin(phase(freq) * i) + sum }
|
23
|
+
buffer[i] = (sound * (0x6AFF / freqs.size)).round
|
22
24
|
end
|
23
25
|
|
24
26
|
buffer.start
|
@@ -30,18 +32,18 @@ module ColtraneSynth
|
|
30
32
|
|
31
33
|
def self.extract_frequencies(arg)
|
32
34
|
case arg
|
33
|
-
when Coltrane::Chord then arg.notes.map {|n| n.frequency.octave(4).to_f }
|
35
|
+
when Coltrane::Chord then arg.notes.map { |n| n.frequency.octave(4).to_f }
|
34
36
|
when Coltrane::PitchClass then arg.frequency.octave(4).to_f
|
35
37
|
when Coltrane::Voicing then arg.frequencies.map(&:to_f)
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
39
41
|
def sine_wave(freq, i)
|
40
|
-
Math.sin(phase(freq)*i)
|
42
|
+
Math.sin(phase(freq) * i)
|
41
43
|
end
|
42
44
|
|
43
45
|
def phase(freq)
|
44
46
|
(Math::PI * 2.0 * freq) / SAMPLE_RATE.to_f
|
45
47
|
end
|
46
48
|
end
|
47
|
-
end
|
49
|
+
end
|
data/lib/coltrane_synth/synth.rb
CHANGED
data/lib/core_ext.rb
CHANGED
@@ -22,42 +22,13 @@ class String
|
|
22
22
|
!!match(*args)
|
23
23
|
end
|
24
24
|
|
25
|
-
def interval_quality
|
26
|
-
{
|
27
|
-
'P' => 'Perfect',
|
28
|
-
'm' => 'Minor',
|
29
|
-
'M' => 'Major',
|
30
|
-
'A' => 'Augmented',
|
31
|
-
'd' => 'Diminished'
|
32
|
-
}[self]
|
33
|
-
end
|
34
|
-
|
35
25
|
def symbolize
|
36
|
-
|
26
|
+
underscore.to_sym
|
37
27
|
end
|
38
28
|
end
|
39
29
|
|
40
30
|
# Here we add some syntax sugar to make the code more understandable later
|
41
31
|
class Numeric
|
42
|
-
def interval_name
|
43
|
-
{
|
44
|
-
1 => 'Unison',
|
45
|
-
2 => 'Second',
|
46
|
-
3 => 'Third',
|
47
|
-
4 => 'Fourth',
|
48
|
-
5 => 'Fifth',
|
49
|
-
6 => 'Sixth',
|
50
|
-
7 => 'Seventh',
|
51
|
-
8 => 'Octave',
|
52
|
-
9 => 'Ninth',
|
53
|
-
10 => 'Tenth',
|
54
|
-
11 => 'Eleventh',
|
55
|
-
12 => 'Twelfth',
|
56
|
-
13 => 'Thirteenth',
|
57
|
-
14 => 'Fourteenth',
|
58
|
-
15 => 'Double Octave'
|
59
|
-
}[self % 16]
|
60
|
-
end
|
61
32
|
end
|
62
33
|
|
63
34
|
# Here we add some methods better work with Tries
|
data/lib/os.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module OS
|
2
4
|
class << self
|
3
5
|
def windows?
|
@@ -5,7 +7,7 @@ module OS
|
|
5
7
|
end
|
6
8
|
|
7
9
|
def mac?
|
8
|
-
|
10
|
+
(/darwin/ =~ RUBY_PLATFORM) != nil
|
9
11
|
end
|
10
12
|
|
11
13
|
def unix?
|
@@ -16,4 +18,4 @@ module OS
|
|
16
18
|
unix? && !mac?
|
17
19
|
end
|
18
20
|
end
|
19
|
-
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coltrane
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1
|
4
|
+
version: 2.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pedro Maciel
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-03-
|
11
|
+
date: 2018-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: dry-monads
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.4'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: paint
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -93,6 +107,7 @@ files:
|
|
93
107
|
- ".rspec"
|
94
108
|
- ".rubocop.yml"
|
95
109
|
- ".ruby-version"
|
110
|
+
- ".travis.yml"
|
96
111
|
- CHANGELOG.md
|
97
112
|
- CODE_OF_CONDUCT.md
|
98
113
|
- Gemfile
|
@@ -173,6 +188,7 @@ files:
|
|
173
188
|
- lib/coltrane/diatonic_scale.rb
|
174
189
|
- lib/coltrane/errors.rb
|
175
190
|
- lib/coltrane/frequency.rb
|
191
|
+
- lib/coltrane/frequency_interval.rb
|
176
192
|
- lib/coltrane/interval.rb
|
177
193
|
- lib/coltrane/interval_class.rb
|
178
194
|
- lib/coltrane/interval_sequence.rb
|
@@ -223,7 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
223
239
|
version: '0'
|
224
240
|
requirements: []
|
225
241
|
rubyforge_project:
|
226
|
-
rubygems_version: 2.7.
|
242
|
+
rubygems_version: 2.7.6
|
227
243
|
signing_key:
|
228
244
|
specification_version: 4
|
229
245
|
summary: It deals with all sorts of calculations around music theory and allows for
|