wtf_chord 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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