wtf_chord 0.2.1 → 0.6.0

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
- SHA1:
3
- metadata.gz: 23feadfbf5375e890423135cc86a56d9b70af3e8
4
- data.tar.gz: aaa6a0d46fbeb51e715306da3d127b86816ed293
2
+ SHA256:
3
+ metadata.gz: 6b17613170273223d591f45e88733cf89449d8b872088496c7c569a7e053f4e0
4
+ data.tar.gz: 10460d448a476b45fd1ea0c96b6b418458f7c123b83f9bc8f8d45593e6fd1b36
5
5
  SHA512:
6
- metadata.gz: 711ef213b9ea7302e812c122fda26aee2bb305960a0a1fc3f687106948ea401dcfe17eaeac3972d9a42f6bdf22f6189d01255be790bf89194dbb5e6479a3d86c
7
- data.tar.gz: 4c081a0a57e196422c13fa0a40f671e55d2b39ad49f96678c8b87da277d5e242d4d38fd19924d7e0d920444cc290af7d5984208e75f8a1cbc4dbeeddd10e7547
6
+ metadata.gz: 37dc9a3b6f74eeb4615f8ff897982c0a4dff8577316415ce50cd9278968298d2c9a18d24ca885fde1f599c919b6547884983ab38e68f5ae49e33f6671436e8a9
7
+ data.tar.gz: 8d326d7047187a13e778af13928a3e5ac847e56c57109817feab09b17d00a29c2d56a33c9d98d23946ccde52fa5cc65e158f14ee71e59470bdb57ec319514ccb
data/CHANGELOG.md ADDED
@@ -0,0 +1,10 @@
1
+ ## 0.5.0 / 2016-08-17
2
+
3
+ * 2 major features
4
+ * Support chords with bass string mods (like Am/G)
5
+ * Add extra_complexity modifier
6
+
7
+ * 1 bug fixes:
8
+ * Fix fingering equality
9
+
10
+ * Add CHANGELOG.md
data/README.md CHANGED
@@ -31,13 +31,13 @@ Or install it yourself as:
31
31
 
32
32
  Finds fingerings of the requested chord.
33
33
 
34
- v0.2.1
34
+ v0.3.1
35
35
 
36
36
  Options:
37
37
  -h, --help Show command line help
38
38
  --version Show help/version info
39
39
  -n, --amount N Amount of fingering variants to output.
40
- (default: 3)
40
+ (default: 5)
41
41
  -o, --output FORMAT Output format.
42
42
  (default: default)
43
43
  -R, --[no-]rates Output fingering complexity rates
@@ -57,25 +57,25 @@ For example, to print two fingering variants of the `Dm` chord, just run:
57
57
  And you'll get the visual presentation of chords' fingerings:
58
58
 
59
59
  [ × × 0 2 3 1 ]
60
- ––––––––––––––––––
61
- | | | | |
62
- | | | | |
63
- | | | | |
60
+ ——————————————————
61
+ | | | | |
62
+ | | | | |
63
+ | | | | |
64
64
  | | | | | |
65
65
  | | | | | |
66
66
  | | | | | |
67
- ––––––––––––––––––
67
+ ——————————————————
68
68
  D A D F
69
69
 
70
70
  [ × 5 7 7 6 5 ]
71
- ––––––––––––––––––
72
- | | | | V
73
- | | | | |
74
- | | | |
71
+ ——————————————————
72
+ | | | | ◉ ← V
73
+ | | | | |
74
+ | | | |
75
75
  | | | | | |
76
76
  | | | | | |
77
77
  | | | | | |
78
- ––––––––––––––––––
78
+ ——————————————————
79
79
  D A D F A
80
80
 
81
81
  You can get simpler output, using the `--output` option:
@@ -1,68 +1,41 @@
1
1
  require 'wtf_chord/fingering'
2
+ require 'wtf_chord/fingerings_generator'
2
3
 
3
4
  module WTFChord
4
5
  class Chord
5
- MAX_DIST = 5
6
- MAX_FRET = 7
6
+ BASS_MATCH = /(?<=[\\\/])[A-H][b#]?(?=$)/
7
7
 
8
- attr_reader :pitch, :steps, :notes, :name
8
+ attr_reader :pitch, :steps, :notes, :name, :bass
9
9
 
10
10
  def initialize(note, name)
11
11
  @pitch = note.is_a?(Pitch) ? note : WTFChord.note(note)
12
12
  @name = "#{@pitch.key}#{name}".freeze
13
13
  @steps = Array(WTFChord.rules[name])
14
14
  @notes = @steps.map { |dist| (@pitch + dist).note }.tap(&:uniq!)
15
- end
16
15
 
17
- def inspect
18
- "#{name} (#{@notes.map(&:key) * ' - '})"
19
- end
20
-
21
- def fingerings(limit = 3)
22
- list = []
23
-
24
- (0..MAX_FRET).each do |from_fret|
25
- f = get_fingering(from_fret)
26
- next if list.include?(f)
27
- list << f if all_notes?(f.used_strings)
16
+ BASS_MATCH.match(@name) do |m|
17
+ @bass = WTFChord.note(m[0]).note
28
18
  end
29
-
30
- sort_fingerings(list, limit)
31
19
  end
32
20
 
33
- def get_fingering(from_fret = 0)
34
- to_fret = from_fret + MAX_DIST
35
- Fingering.new(GUITAR) do |f|
36
- f.strings.each do |s|
37
- fret = (from_fret..to_fret).detect { |dist| @notes.include?((s.original + dist).note) }
38
- fret ? s.hold_on(fret) : s.dead
39
- end
40
-
41
- adjust_fingering(f.used_strings[0], to_fret, 0) while should_adjust?(f.used_strings[0], 0)
42
- end
21
+ def fingerings(limit = nil)
22
+ FingeringsGenerator.new(self).call[0, limit || 5]
43
23
  end
44
24
 
45
- def all_notes?(strings)
46
- snotes = strings.map(&:note).tap(&:uniq!)
47
- @notes.all? { |n| snotes.include?(n) }
25
+ def third_tone
26
+ @third_tone ||= @notes[@steps.size > 3 ? 2 : -1]
48
27
  end
49
28
 
50
- def adjust_fingering(string, to_fret, i = 0)
51
- while string.fret < to_fret.pred
52
- string.hold_on(string.fret + 1)
53
- break if @notes.include?(string.note)
54
- end
55
-
56
- string.dead if !string.dead? && string.note != @notes[i]
29
+ def bass?
30
+ !!@bass
57
31
  end
58
32
 
59
- def should_adjust?(string, i = 0)
60
- string && string.note != @notes[i]
33
+ def original_bass
34
+ @notes[0]
61
35
  end
62
36
 
63
- def sort_fingerings(list, limit)
64
- list.sort_by!(&:complexity)
65
- list[0...limit].sort_by!(&:min_fret)
37
+ def inspect
38
+ "#{name} (#{@notes.map(&:key) * ' - '})"
66
39
  end
67
40
  end
68
41
  end
data/lib/wtf_chord/cli.rb CHANGED
@@ -7,14 +7,15 @@ module WTFChord
7
7
  include Methadone::CLILogging
8
8
 
9
9
  main do |name|
10
- chord = WTFChord.chord(name)
11
- fingerings = chord.fingerings(options['amount'])
12
- formatter = WTFChord::Formatter.new(options['output'], options['rates'])
10
+ chord = WTFChord.chord(name)
11
+ formatter = WTFChord::Formatter.new(options['output'], options['rates'])
13
12
 
14
13
  debug { "Output using formatter: #{formatter.formatter.to_s}\n" }
15
14
 
15
+ options['amount'] = 1 if options['output'] == 'piano'
16
+
16
17
  puts chord.inspect, nil
17
- formatter.(*fingerings)
18
+ puts formatter[*chord.fingerings(options['amount'])] * formatter.separator
18
19
  end
19
20
 
20
21
  version VERSION
@@ -31,7 +32,7 @@ module WTFChord
31
32
  ##
32
33
  # Options
33
34
  #
34
- options['amount'] = 3
35
+ options['amount'] = 5
35
36
  options['output'] = 'default'
36
37
  options['rates'] = false
37
38
 
@@ -6,19 +6,29 @@ module WTFChord
6
6
 
7
7
  def rate
8
8
  frets = @fingering.holded_strings.map(&:fret)
9
- barre = frets.uniq.keep_if { |o| frets.count(o) >= 2 }.min
10
- barre_strings = barre ? frets.count(barre).pred : 0
9
+ barre = frets.uniq.keep_if { |o| frets.count(o) >= 2 }
10
+ barre_strings = barre.min ? frets.count(barre.min).pred : 0
11
11
 
12
12
  base_rate = begin
13
- Rational(holded_strings - barre_strings, 6).to_f +
14
- Rational(finger_dist(frets), 5).to_f
13
+ Rational(holded_strings - barre_strings, 4).to_f +
14
+ Rational(finger_dist(@fingering.used_strings.map(&:fret)), 4).to_f
15
15
  end
16
16
 
17
+ base_rate += 0.5 if (holded_strings - barre_strings) > 4
18
+
17
19
  # p [@fingering, holded_strings, barre_strings]
18
20
 
19
- base_rate += 1 if (barre_strings > 2 || frets.uniq.size > 3) && complex_barre?(barre, frets)
21
+ if holded_strings > 4
22
+ uniq_frets = frets.uniq.size
23
+
24
+ if barre.size > 1 && uniq_frets == 3 && frets.count(barre.max) > barre_strings.next
25
+ base_rate += 1 if complex_barre?(barre.max, frets)
26
+ elsif barre_strings.next >= 2 || uniq_frets.size > 3
27
+ base_rate += 1 if complex_barre?(barre.min, frets)
28
+ end
29
+ end
20
30
 
21
- base_rate
31
+ base_rate + @fingering.extra_complexity
22
32
  end
23
33
 
24
34
  private
@@ -4,14 +4,18 @@ require 'wtf_chord/formatter'
4
4
 
5
5
  module WTFChord
6
6
  class Fingering < Fretboard
7
- def initialize(guitar)
7
+ attr_accessor :extra_complexity
8
+
9
+ def initialize(guitar, fingers = nil)
8
10
  @capo = guitar.capo
9
11
  @strings = guitar.strings.map(&:dup)
12
+ @extra_complexity = 0.0
13
+ set_fingers(fingers) if fingers.is_a?(Array)
10
14
  yield(self) if block_given?
11
15
  end
12
16
 
13
17
  def code
14
- @code ||= strings.map(&:code).pack("c*")
18
+ strings.map(&:code).pack("c*")
15
19
  end
16
20
 
17
21
  def == other
@@ -22,6 +26,14 @@ module WTFChord
22
26
  end
23
27
  end
24
28
 
29
+ def eql?(other)
30
+ super || self == other
31
+ end
32
+
33
+ def hash
34
+ strings.map(&:code).hash
35
+ end
36
+
25
37
  def complexity
26
38
  complexity_counter.rate
27
39
  end
@@ -42,6 +54,14 @@ module WTFChord
42
54
  @strings.reject(&:dead?)
43
55
  end
44
56
 
57
+ def find_used_string_for(note)
58
+ used = used_strings
59
+ if idx = used.index(note)
60
+ string = used[idx]
61
+ yield(strings.index(string), string)
62
+ end
63
+ end
64
+
45
65
  def min_fret
46
66
  holded_strings.min.fret
47
67
  end
@@ -0,0 +1,120 @@
1
+ module WTFChord
2
+ class Chord
3
+ end
4
+
5
+ class FingeringsGenerator < DelegateClass(Chord)
6
+ MAX_DIST = 5
7
+ MAX_FRET = 7
8
+
9
+ def fingerings
10
+ @fingerings ||= []
11
+ end
12
+
13
+ def call
14
+ fingerings.clear
15
+
16
+ (0...MAX_FRET).each do |from|
17
+ to = from + MAX_DIST
18
+ generate(from...to) do |variant|
19
+ fingerings << set_bass(variant) if filter_variant(variant)
20
+ end
21
+ end
22
+
23
+ fingerings.uniq!
24
+ fingerings.sort_by!(&:complexity)
25
+ end
26
+
27
+ private
28
+
29
+ def generate(fret_range)
30
+ combinations = WTFChord.guitar.strings.map.with_index do |s, index|
31
+ fret_range.
32
+ select { |dist| pitch = s.original + dist; has_note?(pitch) }.
33
+ tap { |frets| frets << nil if frets.size == 0 }
34
+ end
35
+
36
+ combinations.inject(&:product).each do |fingers|
37
+ fingers.flatten!
38
+
39
+ Fingering.new(WTFChord.guitar, fingers) do |variant|
40
+ adjust(variant)
41
+ yield(variant)
42
+ end
43
+ end
44
+ end
45
+
46
+ def filter_variant(variant)
47
+ used_strings = variant.used_strings
48
+ used_notes = used_strings.map(&:note)
49
+ tones_count = notes.map { |n| used_notes.count(n) }
50
+
51
+ !fingerings.include?(variant) &&
52
+ basetone?(used_strings[0]) &&
53
+ (
54
+ (third?(used_strings[1]) || third?(used_strings[2])) ||
55
+ (last?(used_strings[1]) || last?(used_strings[2]))
56
+ ) &&
57
+ all_notes?(used_notes) &&
58
+ used_notes.each_cons(2).none? { |(l, r)| l == r } &&
59
+ tones_count.all? { |n| tones_count[0] >= n || tones_count[notes.index(third_tone)] >= n } &&
60
+ variant.complexity <= 2.25
61
+ end
62
+
63
+ def adjust(fingering)
64
+ while (string = fingering.used_strings[0]) && !basetone?(string)
65
+ string.dead if !string.dead?
66
+ break if fingering.used_strings.size == 4
67
+ end
68
+ end
69
+
70
+ def set_bass(variant)
71
+ if bass?
72
+ variant.find_used_string_for(original_bass) do |idx, bass_string|
73
+ try_set_bass_on(variant, idx) or begin
74
+ 4.times do |i|
75
+ next if i == idx
76
+ if try_set_bass_on(variant, i)
77
+ bass_string.dead
78
+ break
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ variant
86
+ end
87
+
88
+ def try_set_bass_on(variant, idx)
89
+ bass_string = variant.strings[idx].dup
90
+ distance = bass_string.distance_to(bass)
91
+
92
+ if distance >= 0 && distance < 5 && (distance - variant.min_fret) > -3
93
+ variant.extra_complexity += 0.5 if distance < variant.min_fret
94
+ variant.strings[idx].hold_on(distance)
95
+ true
96
+ end
97
+ end
98
+
99
+ def all_notes?(used_notes)
100
+ notes.all? { |n| used_notes.include?(n) }
101
+ end
102
+
103
+ def has_note?(value)
104
+ value = value.note if !value.is_a?(Note) && value.respond_to?(:note)
105
+ notes.include?(value)
106
+ end
107
+
108
+ def basetone?(string)
109
+ string && string.note == notes[0]
110
+ end
111
+
112
+ def third?(string)
113
+ string && (string.note == third_tone)
114
+ end
115
+
116
+ def last?(string)
117
+ string && (string.note == notes[-1])
118
+ end
119
+ end
120
+ end
@@ -9,19 +9,21 @@ module WTFChord
9
9
  end
10
10
 
11
11
  def call(*fingerings)
12
- formatter.with_rates(@with_rates) do |f|
13
- puts (fingerings.map(&f) * f.separator)
14
- end
12
+ formatter.with_rates(@with_rates) { |f| fingerings.map(&f) }
15
13
  end
16
14
 
17
15
  alias :[] :call
18
16
 
17
+ def separator
18
+ formatter.separator
19
+ end
20
+
19
21
  def formatter
20
- WTFChord::Formatters.const_get(formatter_name)
22
+ Formatters.const_get(formatter_name)
21
23
  end
22
24
 
23
25
  def formatter?
24
- WTFChord::Formatters.const_defined?(formatter_name)
26
+ Formatters.const_defined?(formatter_name)
25
27
  end
26
28
 
27
29
  def formatter_name
@@ -31,6 +31,10 @@ module WTFChord
31
31
  def draw
32
32
  end
33
33
 
34
+ def keys
35
+ strings.reject(&:dead?).map(&:key)
36
+ end
37
+
34
38
  def with_rates?
35
39
  !!@with_rates
36
40
  end
@@ -1,25 +1,28 @@
1
+ require 'wtf_chord/helpers/roman_numbers_helper'
2
+
1
3
  module WTFChord
2
4
  module Formatters
3
5
  class Default < Base
4
6
  OPEN = "|".freeze
5
- HORIZ = "".freeze
7
+ HORIZ = "".freeze
6
8
  SPACE = " ".freeze
7
- BULL = "\u2022".freeze
8
- LATIN = %w(0 I II III IV V VI VII VIII IX X XII XIII).freeze
9
+ BULL = "\u25C9".freeze
9
10
  NEWLINE = "\n".freeze
11
+ COMPLEXITY_FORMAT = " (complexity: %.2f)".freeze
12
+ EMPTY_STRING = Array.new(FRETS, OPEN).freeze
10
13
 
11
- def self.separator
12
- "\n\n".freeze
13
- end
14
+ include RomanNumbersHelper
14
15
 
15
16
  def draw
16
- [
17
- "[ #{head} ]#{capo}",
18
- " #{border}",
19
- *fret_rows,
20
- " #{border}",
21
- " #{string_keys}#{rate}"
22
- ] * NEWLINE
17
+ <<-EOF.gsub(/^\s+\|/, '')
18
+ |[ #{head} ] #{capo}
19
+ | #{border}
20
+ #{fret_rows.map.with_index { |row, index|
21
+ " | #{row} #{roman_min_fret if index == 0}"
22
+ }.join("\n")}
23
+ | #{border}
24
+ | #{string_keys}#{rate}
25
+ EOF
23
26
  end
24
27
 
25
28
  private
@@ -29,11 +32,15 @@ module WTFChord
29
32
  end
30
33
 
31
34
  def capo
32
- " (capo #{to_latin @fret.capo})" if @fret.capo > 0
35
+ "(capo #{romanize(@fret.capo)})" if @fret.capo > 0
36
+ end
37
+
38
+ def roman_min_fret
39
+ " ← #{romanize(min_fret)}" if min_fret > 1
33
40
  end
34
41
 
35
42
  def rate
36
- " (complexity: %.2f)" % @fret.complexity if with_rates?
43
+ COMPLEXITY_FORMAT % @fret.complexity if with_rates?
37
44
  end
38
45
 
39
46
  def border
@@ -41,27 +48,21 @@ module WTFChord
41
48
  end
42
49
 
43
50
  def string_rows
44
- strings.map { |string| draw_string(string.fret) }
51
+ strings.map { |string| draw_string(string) }
45
52
  end
46
53
 
47
54
  def fret_rows
48
- string_rows.transpose.map! { |row| " #{row * SPACE} " }.tap do |rows|
49
- rows[0] << " #{to_latin min_fret}" if min_fret > 1
50
- end
55
+ return to_enum(__method__) unless block_given?
56
+ string_rows.transpose.each { |row| yield(row * SPACE) }
51
57
  end
52
58
 
53
59
  def string_keys
54
60
  strings.map { |s| s.dead? ? SPACE : "%-2s" % s.key } * " "
55
61
  end
56
62
 
57
- def to_latin(num)
58
- LATIN[num]
59
- end
60
-
61
- def draw_string(fret)
62
- Array.new(FRETS, OPEN).tap do |rows|
63
- rows[(fret - min_fret.pred).pred] = BULL if fret.to_i > 0
64
- end
63
+ def draw_string(string)
64
+ EMPTY_STRING.dup.
65
+ tap { |rows| rows[string.fret - min_fret] = BULL if string.holded? }
65
66
  end
66
67
  end
67
68
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "wtf_chord/keyboard"
4
+
5
+ module WTFChord
6
+ module Formatters
7
+ class Piano < Base
8
+ def draw
9
+ [
10
+ unique_notes.sort.join(" - "),
11
+ Keyboard.press(*unique_notes.map(&:position))
12
+ ].join("\n\n")
13
+ end
14
+
15
+ def unique_notes
16
+ strings.reject(&:dead?).each_with_object([[], []]) do |string, (positions, notes)|
17
+ unless positions.include?(string.note.position)
18
+ positions << string.note.position
19
+ notes << string.note
20
+ end
21
+ end[1]
22
+ end
23
+ end
24
+ end
25
+ end
@@ -23,6 +23,14 @@ module WTFChord
23
23
  self
24
24
  end
25
25
 
26
+ def with_capo(capo)
27
+ capo_was = @capo
28
+ set_capo(capo)
29
+ yield
30
+ ensure
31
+ set_capo(capo_was)
32
+ end
33
+
26
34
  def fingers
27
35
  @strings.map { |string| string.dead? ? DEAD : string.fret }
28
36
  end
@@ -48,6 +48,13 @@ module WTFChord
48
48
  dead? ? -1 : to_i
49
49
  end
50
50
 
51
+ def distance_to(pitch)
52
+ pos = 0
53
+ opened = dup.open
54
+ pos += 1 while (opened + pos) != pitch
55
+ pos
56
+ end
57
+
51
58
  def <=> other
52
59
  return if dead?
53
60
  case other
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WTFChord
4
+ module RomanNumbersHelper
5
+ ROMAN_SYMBOLS ||= ("\u2160".."\u216B").to_a.unshift(nil).freeze
6
+
7
+ def romanize(number)
8
+ ROMAN_SYMBOLS[number]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WTFChord
4
+ class Keyboard
5
+ FRAME = <<~EOF
6
+ ┌─┬─┬┬─┬─┬─┬─┬┬─┬┬─┬─┐
7
+ │ │ ││ │ │ │ ││ ││ │ │
8
+ │ └┬┘└┬┘ │ └┬┘└┬┘└┬┘ │
9
+ │ │ │ │ │ │ │ │
10
+ └──┴──┴──┴──┴──┴──┴──┘
11
+ EOF
12
+
13
+ Key = Struct.new(:offset)
14
+ class Key
15
+ singleton_class.attr_accessor :select_symbol
16
+ singleton_class.alias_method :[], :new
17
+
18
+ def select(frame)
19
+ frame[offset] = self.class.select_symbol
20
+ frame
21
+ end
22
+ end
23
+
24
+ W = Class.new(Key) { self.select_symbol = "▐▌" }
25
+ B = Class.new(Key) { self.select_symbol = "█" }
26
+
27
+ KEYS = {
28
+ 1 => W[70...72],
29
+ 2 => B[26...27],
30
+ 3 => W[73...75],
31
+ 4 => B[29...30],
32
+ 5 => W[76...78],
33
+ 6 => W[79...81],
34
+ 7 => B[35...36],
35
+ 8 => W[82...84],
36
+ 9 => B[38...39],
37
+ 10 => W[85...87],
38
+ 11 => B[41...42],
39
+ 12 => W[88...90]
40
+ }
41
+
42
+ def self.press(*positions)
43
+ positions.each_with_object(FRAME.dup) do |pos, frame|
44
+ KEYS.fetch(pos).select(frame)
45
+ end
46
+ end
47
+ end
48
+ end
@@ -25,8 +25,9 @@ module WTFChord
25
25
 
26
26
  def == other
27
27
  case other
28
- when String then other.casecmp(@key).zero?
29
- when Integer, Note then other == @position
28
+ when String then other.casecmp(@key).zero? || aliases.any? { |a| other.casecmp(a.key).zero? }
29
+ when Integer then other == @position
30
+ when Note then other.position == @position
30
31
  end
31
32
  end
32
33
 
@@ -46,6 +46,10 @@ module WTFChord
46
46
  move -amount
47
47
  end
48
48
 
49
+ def -@
50
+ -to_i
51
+ end
52
+
49
53
  def to_i
50
54
  (@octave * 12) + @note.position
51
55
  end
@@ -23,7 +23,9 @@ module WTFChord
23
23
  name.match(pattern) do |m|
24
24
  base = chords[m[:name]] || chords["M"]
25
25
  steps.concat(base)
26
- steps.concat(extra[m[:ext]]) if m[:ext] && m[:ext].length <= (6 - steps.length)
26
+
27
+ ext = extra[m[:ext]] if m[:ext]
28
+ steps.concat(ext) if ext
27
29
  end
28
30
 
29
31
  steps.tap(&:uniq!)
@@ -63,5 +63,11 @@ module WTFChord
63
63
  ScaleArray.build(*chromatic_scale).freeze
64
64
  end
65
65
 
66
- GUITAR ||= Fretboard.new(*%w(E2 A2 D3 G3 B3 E4))
66
+ def self.guitar=(guitar)
67
+ Thread.current[:wtf_guitar] = guitar
68
+ end
69
+
70
+ def self.guitar
71
+ Thread.current[:wtf_guitar] ||= Fretboard.new(*%w(E2 A2 D3 G3 B3 E4))
72
+ end
67
73
  end
@@ -1,3 +1,3 @@
1
1
  module WTFChord
2
- VERSION = "0.2.1"
2
+ VERSION = "0.6.0"
3
3
  end
data/wtf_chord.gemspec CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.add_runtime_dependency "methadone"
24
24
 
25
- spec.add_development_dependency "bundler", ">= 1.11", "< 2"
26
- spec.add_development_dependency "rake", ">= 10.0", "< 12"
25
+ spec.add_development_dependency "bundler"
26
+ spec.add_development_dependency "rake"
27
27
  spec.add_development_dependency "rspec", ">= 3.0", "< 4"
28
28
  end
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.2.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-04-03 00:00:00.000000000 Z
11
+ date: 2021-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: methadone
@@ -30,40 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.11'
34
- - - "<"
35
- - !ruby/object:Gem::Version
36
- version: '2'
33
+ version: '0'
37
34
  type: :development
38
35
  prerelease: false
39
36
  version_requirements: !ruby/object:Gem::Requirement
40
37
  requirements:
41
38
  - - ">="
42
39
  - !ruby/object:Gem::Version
43
- version: '1.11'
44
- - - "<"
45
- - !ruby/object:Gem::Version
46
- version: '2'
40
+ version: '0'
47
41
  - !ruby/object:Gem::Dependency
48
42
  name: rake
49
43
  requirement: !ruby/object:Gem::Requirement
50
44
  requirements:
51
45
  - - ">="
52
46
  - !ruby/object:Gem::Version
53
- version: '10.0'
54
- - - "<"
55
- - !ruby/object:Gem::Version
56
- version: '12'
47
+ version: '0'
57
48
  type: :development
58
49
  prerelease: false
59
50
  version_requirements: !ruby/object:Gem::Requirement
60
51
  requirements:
61
52
  - - ">="
62
53
  - !ruby/object:Gem::Version
63
- version: '10.0'
64
- - - "<"
65
- - !ruby/object:Gem::Version
66
- version: '12'
54
+ version: '0'
67
55
  - !ruby/object:Gem::Dependency
68
56
  name: rspec
69
57
  requirement: !ruby/object:Gem::Requirement
@@ -95,6 +83,7 @@ files:
95
83
  - ".gitignore"
96
84
  - ".rspec"
97
85
  - ".travis.yml"
86
+ - CHANGELOG.md
98
87
  - Gemfile
99
88
  - README.md
100
89
  - Rakefile
@@ -107,12 +96,16 @@ files:
107
96
  - lib/wtf_chord/cli.rb
108
97
  - lib/wtf_chord/complexity_counter.rb
109
98
  - lib/wtf_chord/fingering.rb
99
+ - lib/wtf_chord/fingerings_generator.rb
110
100
  - lib/wtf_chord/formatter.rb
111
101
  - lib/wtf_chord/formatters/base.rb
112
102
  - lib/wtf_chord/formatters/default.rb
103
+ - lib/wtf_chord/formatters/piano.rb
113
104
  - lib/wtf_chord/formatters/simple.rb
114
105
  - lib/wtf_chord/fretboard.rb
115
106
  - lib/wtf_chord/guitar_string.rb
107
+ - lib/wtf_chord/helpers/roman_numbers_helper.rb
108
+ - lib/wtf_chord/keyboard.rb
116
109
  - lib/wtf_chord/note.rb
117
110
  - lib/wtf_chord/pitch.rb
118
111
  - lib/wtf_chord/rules.rb
@@ -137,10 +130,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
130
  - !ruby/object:Gem::Version
138
131
  version: '0'
139
132
  requirements: []
140
- rubyforge_project:
141
- rubygems_version: 2.5.1
133
+ rubygems_version: 3.0.3
142
134
  signing_key:
143
135
  specification_version: 4
144
136
  summary: "‘WTF Chord?’ is the Ruby guitar chords generator library."
145
137
  test_files: []
146
- has_rdoc: