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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cec796fdac73df072faef8d89c98f6fc37aded7f
4
- data.tar.gz: 17772eb9d7105e1445ff40e6873c37d12914cca7
3
+ metadata.gz: 42f6e0b2d54785364d40dfc28d48ac718a62feb3
4
+ data.tar.gz: 4747da8acf163bdeea61e0ab1902f6bf6d812445
5
5
  SHA512:
6
- metadata.gz: 945c5110c7e52340a4eca72385710d9cfa031cb647c2a2f8ae8207af7179467f3dc72059dc42bcf8b64083d0338644f018f85f5be551d53e4b722d3cd76f5e63
7
- data.tar.gz: ba92873418bb4224f7dbf841501b02694c2fda562ea86030b4c918364b004c74b8f9d3bca6eb38168aeaf939934829ddc6186b44d09d79bc2daa86e01143a89e
6
+ metadata.gz: f34f794282e89a4f924c04bf74ea234b4e484bd95a4f78e583dae57e27133775a86fd8fa817928c702fadafedd31fa2a8805ce78c7e47ff56958afbaa75108a0
7
+ data.tar.gz: 6fdf726a6bb8e8f2ad2446b40347f28a2e47692944fc879ed35b80366650bc770eedfa6a9c29a6a846e74ada7a505a6ffc944e5cc0769c9574688fc153fd0339
data/README.md CHANGED
@@ -1,8 +1,13 @@
1
- # WTFChord
1
+ # WTF Chord?
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/wtf_chord`. To experiment with that code, run `bin/console` for an interactive prompt.
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
- TODO: Delete this and the text above, and describe your gem
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
- ## Usage
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
- $ wtfchord F#dim
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/[USERNAME]/wtf_chord.
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]).draw_fingerings(ARGV[1]&.to_i || 3)
8
+ chord = WTFChord.chord(ARGV[0])
9
+
10
+ puts chord.inspect, nil
11
+ chord.draw_fingerings(ARGV[1]&.to_i || 3)
@@ -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
- fingering = get_fingering(from_fret)
23
-
24
- next if list.include?(fingering)
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
- GUITAR.dup.tap do |guitar|
40
- guitar.strings.each do |s|
41
- fret = (from_fret..(from_fret+MAX_DIST)).detect { |dist| @notes.include?((s.original + dist).note) }
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
- while guitar.used_strings[0] && guitar.used_strings[0].note != @notes[0]
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
@@ -48,6 +48,14 @@ module WTFChord
48
48
  dead? ? -1 : to_i
49
49
  end
50
50
 
51
+ def <=> other
52
+ return if dead?
53
+ case other
54
+ when Integer then @fret <=> other
55
+ when GuitarString then @fret <=> other.fret
56
+ end
57
+ end
58
+
51
59
  private
52
60
 
53
61
  def calculate_note!
@@ -1,6 +1,6 @@
1
1
  require 'wtf_chord/note'
2
2
  require 'wtf_chord/pitch'
3
- require 'wtf_chord/fingerboard'
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 ||= Fingerboard.new(*%w(E2 A2 D3 G3 B3 E4))
66
+ GUITAR ||= Fretboard.new(*%w(E2 A2 D3 G3 B3 E4))
67
67
  end
@@ -1,3 +1,3 @@
1
1
  module WTFChord
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
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? is a Ruby Gem for generating guitar chords.}
13
- spec.description = %q{WTF Chord? provides the library and CLI-tool for generating guitar chords.}
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.0
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-29 00:00:00.000000000 Z
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? provides the library and CLI-tool for generating guitar chords.
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/fingerboard.rb
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? is a Ruby Gem for generating guitar chords.
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