wtf_chord 0.1.0 → 0.1.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/README.md +37 -7
- data/exe/wtfchord +4 -1
- data/lib/wtf_chord/chord.rb +27 -17
- data/lib/wtf_chord/complexity_counter.rb +41 -0
- data/lib/wtf_chord/fingering.rb +51 -0
- data/lib/wtf_chord/fretboard.rb +36 -0
- data/lib/wtf_chord/guitar_string.rb +8 -0
- data/lib/wtf_chord/scale.rb +2 -2
- data/lib/wtf_chord/version.rb +1 -1
- data/wtf_chord.gemspec +4 -2
- metadata +7 -5
- data/lib/wtf_chord/fingerboard.rb +0 -102
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42f6e0b2d54785364d40dfc28d48ac718a62feb3
|
4
|
+
data.tar.gz: 4747da8acf163bdeea61e0ab1902f6bf6d812445
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f34f794282e89a4f924c04bf74ea234b4e484bd95a4f78e583dae57e27133775a86fd8fa817928c702fadafedd31fa2a8805ce78c7e47ff56958afbaa75108a0
|
7
|
+
data.tar.gz: 6fdf726a6bb8e8f2ad2446b40347f28a2e47692944fc879ed35b80366650bc770eedfa6a9c29a6a846e74ada7a505a6ffc944e5cc0769c9574688fc153fd0339
|
data/README.md
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
-
#
|
1
|
+
# WTF Chord?
|
2
2
|
|
3
|
-
|
3
|
+
‘WTF Chord?’ is the Ruby guitar chords generator library & cli tool, which also contains some abstraction for musical mathematics. Chords generator is a common but a not only mission, the library is ready for extending for generating scales.
|
4
4
|
|
5
|
-
|
5
|
+
Some features:
|
6
|
+
|
7
|
+
* Tones math methods.
|
8
|
+
* Finding chords by names with many variants of fingering.
|
9
|
+
* CLI tool `wtfchord` to quickly find chord and draw it's fingerings to your terminal.
|
10
|
+
* Extendable rules (pending).
|
6
11
|
|
7
12
|
## Installation
|
8
13
|
|
@@ -20,9 +25,35 @@ Or install it yourself as:
|
|
20
25
|
|
21
26
|
$ gem install wtf_chord
|
22
27
|
|
23
|
-
##
|
28
|
+
## CLI-tool usage
|
29
|
+
|
30
|
+
For example, to print two fingering variants of the `Dm` chord, just run:
|
31
|
+
|
32
|
+
$ wtfchord Dm 2
|
24
33
|
|
25
|
-
|
34
|
+
And you'll get the visual presentation of chords' fingerings:
|
35
|
+
|
36
|
+
[ × × 0 2 3 1 ]
|
37
|
+
––––––––––––––––––
|
38
|
+
| | | | | •
|
39
|
+
| | | • | |
|
40
|
+
| | | | • |
|
41
|
+
| | | | | |
|
42
|
+
| | | | | |
|
43
|
+
| | | | | |
|
44
|
+
––––––––––––––––––
|
45
|
+
D A D F
|
46
|
+
|
47
|
+
[ × 5 7 7 6 5 ]
|
48
|
+
––––––––––––––––––
|
49
|
+
| • | | | • V
|
50
|
+
| | | | • |
|
51
|
+
| | • • | |
|
52
|
+
| | | | | |
|
53
|
+
| | | | | |
|
54
|
+
| | | | | |
|
55
|
+
––––––––––––––––––
|
56
|
+
D A D F A
|
26
57
|
|
27
58
|
## Development
|
28
59
|
|
@@ -32,5 +63,4 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
63
|
|
33
64
|
## Contributing
|
34
65
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
36
|
-
|
66
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/estum/wtf_chord.
|
data/exe/wtfchord
CHANGED
@@ -5,4 +5,7 @@ $:.unshift File.expand_path('../../lib', __FILE__)
|
|
5
5
|
require 'rubygems' unless Object.const_defined?(:Gem)
|
6
6
|
require "wtf_chord"
|
7
7
|
|
8
|
-
WTFChord.chord(ARGV[0])
|
8
|
+
chord = WTFChord.chord(ARGV[0])
|
9
|
+
|
10
|
+
puts chord.inspect, nil
|
11
|
+
chord.draw_fingerings(ARGV[1]&.to_i || 3)
|
data/lib/wtf_chord/chord.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'wtf_chord/fingering'
|
2
|
+
|
1
3
|
module WTFChord
|
2
4
|
class Chord
|
3
5
|
MAX_DIST = 5
|
@@ -19,32 +21,23 @@ module WTFChord
|
|
19
21
|
def fingerings(limit = 3)
|
20
22
|
list = []
|
21
23
|
(0..MAX_FRET).each do |from_fret|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
if all_notes?(fingering.used_strings)
|
27
|
-
list << fingering
|
28
|
-
end
|
24
|
+
f = get_fingering(from_fret)
|
25
|
+
next if list.include?(f)
|
26
|
+
list << f if all_notes?(f.used_strings)
|
29
27
|
end
|
30
28
|
|
31
29
|
list.sort_by!(&:complexity)[0...limit].sort_by!(&:min_fret)
|
32
30
|
end
|
33
31
|
|
34
|
-
def draw_fingerings(limit = 3)
|
35
|
-
puts (fingerings(limit).map(&:draw) * "\n\n")
|
36
|
-
end
|
37
|
-
|
38
32
|
def get_fingering(from_fret = 0)
|
39
|
-
|
40
|
-
|
41
|
-
|
33
|
+
to_fret = from_fret + MAX_DIST
|
34
|
+
Fingering.new(GUITAR) do |f|
|
35
|
+
f.strings.each do |s|
|
36
|
+
fret = (from_fret..to_fret).detect { |dist| @notes.include?((s.original + dist).note) }
|
42
37
|
fret ? s.hold_on(fret) : s.dead
|
43
38
|
end
|
44
39
|
|
45
|
-
|
46
|
-
guitar.used_strings.detect { |x| !x.dead? && x.note != @notes[0] }&.dead
|
47
|
-
end
|
40
|
+
adjust_fingering(f.used_strings[0], to_fret, 0) while should_adjust?(f.used_strings[0], 0)
|
48
41
|
end
|
49
42
|
end
|
50
43
|
|
@@ -52,5 +45,22 @@ module WTFChord
|
|
52
45
|
snotes = strings.map(&:note).tap(&:uniq!)
|
53
46
|
@notes.all? { |n| snotes.include?(n) }
|
54
47
|
end
|
48
|
+
|
49
|
+
def adjust_fingering(string, to_fret, i = 0)
|
50
|
+
while string.fret < to_fret.pred
|
51
|
+
string.hold_on(string.fret + 1)
|
52
|
+
break if @notes.include?(string.note)
|
53
|
+
end
|
54
|
+
|
55
|
+
string.dead if !string.dead? && string.note != @notes[i]
|
56
|
+
end
|
57
|
+
|
58
|
+
def should_adjust?(string, i = 0)
|
59
|
+
string && string.note != @notes[i]
|
60
|
+
end
|
61
|
+
|
62
|
+
def draw_fingerings(limit = 3)
|
63
|
+
puts (fingerings(limit).map(&:draw) * "\n\n")
|
64
|
+
end
|
55
65
|
end
|
56
66
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module WTFChord
|
2
|
+
class ComplexityCounter
|
3
|
+
def initialize(fingering)
|
4
|
+
@fingering = fingering
|
5
|
+
end
|
6
|
+
|
7
|
+
def rate
|
8
|
+
frets = @fingering.holded_strings.map(&:fret)
|
9
|
+
barre = frets.uniq.keep_if { |o| frets.count(o) > 3 }.max
|
10
|
+
barre_strings = barre ? frets.count(barre).pred : 0
|
11
|
+
|
12
|
+
base_rate = (
|
13
|
+
Rational(holded_strings - barre_strings, total_strings) +
|
14
|
+
Rational(finger_dist(frets), 5)
|
15
|
+
).to_f
|
16
|
+
|
17
|
+
base_rate += 1 if complex_barre?(barre, frets)
|
18
|
+
|
19
|
+
base_rate
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def holded_strings
|
25
|
+
@fingering.strings.count(&:holded?)
|
26
|
+
end
|
27
|
+
|
28
|
+
def total_strings
|
29
|
+
@fingering.strings.size
|
30
|
+
end
|
31
|
+
|
32
|
+
def finger_dist(frets)
|
33
|
+
(frets.max - frets.min).nonzero? || 1
|
34
|
+
end
|
35
|
+
|
36
|
+
def complex_barre?(barre, frets)
|
37
|
+
return false unless barre
|
38
|
+
barre > frets.min
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'wtf_chord/fretboard'
|
2
|
+
require 'wtf_chord/complexity_counter'
|
3
|
+
require 'wtf_chord/drawer'
|
4
|
+
|
5
|
+
module WTFChord
|
6
|
+
class Fingering < Fretboard
|
7
|
+
def initialize(guitar)
|
8
|
+
@capo = guitar.capo
|
9
|
+
@strings = guitar.strings.map(&:dup)
|
10
|
+
yield(self) if block_given?
|
11
|
+
end
|
12
|
+
|
13
|
+
def code
|
14
|
+
@code ||= strings.map(&:code).pack("c*")
|
15
|
+
end
|
16
|
+
|
17
|
+
def == other
|
18
|
+
other.is_a?(Fingering) ? other.code == code : super
|
19
|
+
end
|
20
|
+
|
21
|
+
def complexity
|
22
|
+
complexity_counter.rate
|
23
|
+
end
|
24
|
+
|
25
|
+
def draw
|
26
|
+
Drawer.new(self).draw
|
27
|
+
end
|
28
|
+
|
29
|
+
def set_fingers(fingers)
|
30
|
+
fingers.each_with_index { |f, i| f.nil? ? @strings[i].dead : @strings[i].hold_on(f) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def holded_strings
|
34
|
+
@strings.select(&:holded?)
|
35
|
+
end
|
36
|
+
|
37
|
+
def used_strings
|
38
|
+
@strings.reject(&:dead?)
|
39
|
+
end
|
40
|
+
|
41
|
+
def min_fret
|
42
|
+
holded_strings.min.fret
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def complexity_counter
|
48
|
+
@complexity_counter ||= ComplexityCounter.new(self)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'wtf_chord/guitar_string'
|
2
|
+
|
3
|
+
module WTFChord
|
4
|
+
class Fretboard
|
5
|
+
DEAD = "×".freeze
|
6
|
+
|
7
|
+
attr_reader :strings, :capo
|
8
|
+
|
9
|
+
def initialize(*strings)
|
10
|
+
@capo = 0
|
11
|
+
@strings = strings.map! { |string| GuitarString.new(string, @capo) }
|
12
|
+
end
|
13
|
+
|
14
|
+
def [] idx
|
15
|
+
case idx
|
16
|
+
when 1..@strings.length then @strings[-idx]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_capo(capo = 0)
|
21
|
+
@capo = capo
|
22
|
+
@strings.each { |string| string.set_capo(@capo) }
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def fingers
|
27
|
+
@strings.map { |string| string.dead? ? DEAD : string.fret }
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
"[ #{fingers * " "} ]"
|
32
|
+
end
|
33
|
+
|
34
|
+
alias :inspect :to_s
|
35
|
+
end
|
36
|
+
end
|
data/lib/wtf_chord/scale.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'wtf_chord/note'
|
2
2
|
require 'wtf_chord/pitch'
|
3
|
-
require 'wtf_chord/
|
3
|
+
require 'wtf_chord/fretboard'
|
4
4
|
|
5
5
|
module WTFChord
|
6
6
|
class ScaleArray < Array
|
@@ -63,5 +63,5 @@ module WTFChord
|
|
63
63
|
ScaleArray.build(*chromatic_scale).freeze
|
64
64
|
end
|
65
65
|
|
66
|
-
GUITAR ||=
|
66
|
+
GUITAR ||= Fretboard.new(*%w(E2 A2 D3 G3 B3 E4))
|
67
67
|
end
|
data/lib/wtf_chord/version.rb
CHANGED
data/wtf_chord.gemspec
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
|
2
3
|
lib = File.expand_path('../lib', __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
|
4
6
|
require 'wtf_chord/version'
|
5
7
|
|
6
8
|
Gem::Specification.new do |spec|
|
@@ -9,8 +11,8 @@ Gem::Specification.new do |spec|
|
|
9
11
|
spec.authors = ["Anton"]
|
10
12
|
spec.email = ["anton.estum@gmail.com"]
|
11
13
|
|
12
|
-
spec.summary = %q{WTF Chord
|
13
|
-
spec.description = %q{WTF Chord
|
14
|
+
spec.summary = %q{‘WTF Chord?’ is the Ruby guitar chords generator library.}
|
15
|
+
spec.description = %q{‘WTF Chord?’ is the Ruby guitar chords generator library.}
|
14
16
|
spec.homepage = "https://github.com/estum/wtf_chord"
|
15
17
|
|
16
18
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wtf_chord
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anton
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -70,7 +70,7 @@ dependencies:
|
|
70
70
|
- - "<"
|
71
71
|
- !ruby/object:Gem::Version
|
72
72
|
version: '4'
|
73
|
-
description: WTF Chord
|
73
|
+
description: "‘WTF Chord?’ is the Ruby guitar chords generator library."
|
74
74
|
email:
|
75
75
|
- anton.estum@gmail.com
|
76
76
|
executables:
|
@@ -90,8 +90,10 @@ files:
|
|
90
90
|
- lib/wtf_chord.rb
|
91
91
|
- lib/wtf_chord.yml
|
92
92
|
- lib/wtf_chord/chord.rb
|
93
|
+
- lib/wtf_chord/complexity_counter.rb
|
93
94
|
- lib/wtf_chord/drawer.rb
|
94
|
-
- lib/wtf_chord/
|
95
|
+
- lib/wtf_chord/fingering.rb
|
96
|
+
- lib/wtf_chord/fretboard.rb
|
95
97
|
- lib/wtf_chord/guitar_string.rb
|
96
98
|
- lib/wtf_chord/note.rb
|
97
99
|
- lib/wtf_chord/pitch.rb
|
@@ -121,6 +123,6 @@ rubyforge_project:
|
|
121
123
|
rubygems_version: 2.5.1
|
122
124
|
signing_key:
|
123
125
|
specification_version: 4
|
124
|
-
summary: WTF Chord
|
126
|
+
summary: "‘WTF Chord?’ is the Ruby guitar chords generator library."
|
125
127
|
test_files: []
|
126
128
|
has_rdoc:
|
@@ -1,102 +0,0 @@
|
|
1
|
-
require 'wtf_chord/guitar_string'
|
2
|
-
require 'wtf_chord/drawer'
|
3
|
-
|
4
|
-
module WTFChord
|
5
|
-
class Fingerboard
|
6
|
-
attr_reader :strings, :capo
|
7
|
-
|
8
|
-
def initialize(*strings)
|
9
|
-
@capo = 0
|
10
|
-
@strings = strings.map! do |string|
|
11
|
-
GuitarString.new(string, @capo)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def [] idx
|
16
|
-
case idx
|
17
|
-
when 1..@strings.length then @strings[-idx]
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def set_capo(capo = 0)
|
22
|
-
@capo = capo
|
23
|
-
@strings.each do |string|
|
24
|
-
string.set_capo(@capo)
|
25
|
-
end
|
26
|
-
self
|
27
|
-
end
|
28
|
-
|
29
|
-
def fingers
|
30
|
-
strings.map { |string| string.dead? ? "×" : string.fret }
|
31
|
-
end
|
32
|
-
|
33
|
-
def to_s
|
34
|
-
"[ #{fingers * " "} ]"
|
35
|
-
end
|
36
|
-
|
37
|
-
def initialize_dup(other)
|
38
|
-
super
|
39
|
-
@strings = other.strings.map(&:dup)
|
40
|
-
@code = nil
|
41
|
-
@complexity = nil
|
42
|
-
end
|
43
|
-
|
44
|
-
def set_fingers(fingers)
|
45
|
-
fingers.each_with_index do |f, i|
|
46
|
-
f.nil? ? @strings[i].dead : @strings[i].hold_on(f)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def with_fingers(*fingers)
|
51
|
-
strings_was = @strings.dup
|
52
|
-
set_fingers(fingers)
|
53
|
-
yield(self)
|
54
|
-
self
|
55
|
-
ensure
|
56
|
-
@strings = strings_was
|
57
|
-
end
|
58
|
-
|
59
|
-
def draw
|
60
|
-
Drawer.new(self).draw
|
61
|
-
end
|
62
|
-
|
63
|
-
def count_holded_strings
|
64
|
-
strings.count(&:holded?)
|
65
|
-
end
|
66
|
-
|
67
|
-
def holded_strings
|
68
|
-
strings.select(&:holded?)
|
69
|
-
end
|
70
|
-
|
71
|
-
def used_strings
|
72
|
-
strings.reject(&:dead?)
|
73
|
-
end
|
74
|
-
|
75
|
-
def inspect
|
76
|
-
to_s
|
77
|
-
end
|
78
|
-
|
79
|
-
def code
|
80
|
-
@code ||= strings.map(&:code).pack("c*")
|
81
|
-
end
|
82
|
-
|
83
|
-
def complexity
|
84
|
-
@complexity ||= count_holded_strings * finger_dist
|
85
|
-
end
|
86
|
-
|
87
|
-
def finger_dist
|
88
|
-
frets = holded_strings.map(&:fret)
|
89
|
-
((frets.max - frets.min).nonzero? || 1)
|
90
|
-
end
|
91
|
-
|
92
|
-
def min_fret
|
93
|
-
holded_strings.map(&:fret).min
|
94
|
-
end
|
95
|
-
|
96
|
-
def == other
|
97
|
-
case other
|
98
|
-
when Fingerboard then other.code == code
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|