chords 0.4.1 → 0.4.2
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.
- data/lib/chords/fretboard.rb +26 -14
- data/lib/chords/html_formatter.rb +6 -45
- data/lib/chords/png_formatter.rb +68 -0
- metadata +5 -4
data/lib/chords/fretboard.rb
CHANGED
@@ -108,24 +108,36 @@ module Chords
|
|
108
108
|
tuning_part = fid.sub(fingering_part, '')
|
109
109
|
|
110
110
|
fretboard = Fretboard.new_by_string(tuning_part, 50, formatter_class)
|
111
|
-
over_tens = fingering_part.size - fretboard.open_notes.size
|
112
111
|
|
113
|
-
|
114
|
-
|
112
|
+
max_fret_distance, positions = parse_positions(fingering_part,
|
113
|
+
fretboard.open_notes.size)
|
114
|
+
|
115
|
+
fretboard.formatter.print('', [Fingering.new(fretboard, positions)],
|
116
|
+
opts.merge(:max_fret_distance => max_fret_distance))
|
117
|
+
end
|
118
|
+
|
119
|
+
# parse positions from a string, for example '022100'
|
120
|
+
# returns [max_fret_distance, positions], where max_fret_distance has
|
121
|
+
# a minimum of 2
|
122
|
+
def self.parse_positions(position_str, no_of_strings)
|
123
|
+
position_str.downcase!
|
124
|
+
positions = position_str.scan(/./).map{|pos| pos == 'x' ? nil : pos.to_i}
|
125
|
+
over_tens = positions.size - no_of_strings
|
115
126
|
|
116
|
-
while
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
i += 2
|
122
|
-
pos = "#{pos}#{fingering_part[i+1,1]}".to_i
|
123
|
-
else
|
124
|
-
i += 1
|
127
|
+
while over_tens > 0
|
128
|
+
idx = positions.index{|p| !p.nil? and p > 0 and p < 3}
|
129
|
+
if idx
|
130
|
+
positions[idx] = "#{positions[idx]}#{positions[idx+1]}".to_i
|
131
|
+
positions.delete_at(idx+1)
|
125
132
|
end
|
126
|
-
|
133
|
+
over_tens -= 1
|
127
134
|
end
|
128
|
-
|
135
|
+
max_fret_distance = 2
|
136
|
+
tmp = positions.select{|pos| !pos.nil? and pos > 0}
|
137
|
+
max_fret_distance = tmp.max - tmp.min unless tmp.empty?
|
138
|
+
max_fret_distance = 2 if max_fret_distance < 2
|
139
|
+
|
140
|
+
[max_fret_distance, positions]
|
129
141
|
end
|
130
142
|
|
131
143
|
end
|
@@ -1,7 +1,4 @@
|
|
1
|
-
require '
|
2
|
-
require 'base64'
|
3
|
-
|
4
|
-
Magick::RVG::dpi = 72
|
1
|
+
require 'chords/png_formatter'
|
5
2
|
|
6
3
|
module Chords
|
7
4
|
|
@@ -16,15 +13,15 @@ module Chords
|
|
16
13
|
def initialize(fretboard, cache=NonCache.new)
|
17
14
|
@fretboard = fretboard
|
18
15
|
@cache = cache
|
16
|
+
@png_formatter = PNGFormatter.new(@fretboard)
|
19
17
|
end
|
20
18
|
|
21
19
|
# TODO: accept a separator element in opts
|
22
20
|
def print(title, fingerings, opts={})
|
23
|
-
@max_dist = opts[:max_fret_distance] || Fingering::DEFAULT_MAX_FRET_DISTANCE
|
24
21
|
html = "<h2>#{title}</h2>\n"
|
25
22
|
|
26
23
|
fingerings.each do |fingering|
|
27
|
-
html += get_element(fingering)
|
24
|
+
html += get_element(fingering, opts)
|
28
25
|
end
|
29
26
|
|
30
27
|
if opts[:inline]
|
@@ -39,46 +36,10 @@ module Chords
|
|
39
36
|
|
40
37
|
private
|
41
38
|
|
42
|
-
def get_element(fingering)
|
43
|
-
|
39
|
+
def get_element(fingering, opts)
|
44
40
|
@cache.fetch(fingering.fid) do
|
45
|
-
|
46
|
-
|
47
|
-
x_div = @fretboard.open_notes.size - 1
|
48
|
-
|
49
|
-
y_diff = 215 / (@max_dist + 1)
|
50
|
-
|
51
|
-
(@max_dist+2).times do |n|
|
52
|
-
canvas.line(20, n*y_diff+20, 250, n*y_diff+20)
|
53
|
-
end
|
54
|
-
|
55
|
-
@fretboard.open_notes.each_with_index do |note, i|
|
56
|
-
canvas.line(i*(230/x_div)+20, 20, i*(230/x_div)+20, 230)
|
57
|
-
|
58
|
-
unless [0,nil].include?(fingering[i])
|
59
|
-
canvas.circle(15, i*(230/x_div)+20,
|
60
|
-
fingering.relative(@max_dist)[i]*y_diff - 5)
|
61
|
-
end
|
62
|
-
|
63
|
-
canvas.text(i*(230/x_div)+20, 15) do |txt|
|
64
|
-
txt.tspan((fingering[i] || 'x').to_s).styles(
|
65
|
-
:text_anchor => 'middle',
|
66
|
-
:font_size => 20,
|
67
|
-
:font_family => 'helvetica',
|
68
|
-
:fill => 'black')
|
69
|
-
end
|
70
|
-
canvas.text(i*(230/x_div)+20, 249) do |txt|
|
71
|
-
txt.tspan(note.title).styles(:text_anchor => 'middle',
|
72
|
-
:font_size => 18,
|
73
|
-
:font_family => 'helvetica',
|
74
|
-
:fill => 'black')
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
img = rvg.draw
|
80
|
-
img.format = 'PNG'
|
81
|
-
"<img src=\"data:image/png;base64,#{Base64.encode64(img.to_blob)}\" />\n"
|
41
|
+
png_data = @png_formatter.print(nil, [fingering], opts)
|
42
|
+
"<img src=\"data:image/png;base64,#{Base64.encode64(png_data)}\" />\n"
|
82
43
|
end
|
83
44
|
end
|
84
45
|
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'rvg/rvg' # rmagick's RVG (Ruby Vector Graphics)
|
2
|
+
|
3
|
+
Magick::RVG::dpi = 72
|
4
|
+
|
5
|
+
module Chords
|
6
|
+
|
7
|
+
# Formats a single fingering as png data
|
8
|
+
class PNGFormatter
|
9
|
+
|
10
|
+
def initialize(fretboard)
|
11
|
+
@fretboard = fretboard
|
12
|
+
end
|
13
|
+
|
14
|
+
def print(title, fingerings, opts={})
|
15
|
+
# title omitted
|
16
|
+
raise "Please provide only one fingering" if fingerings.size != 1
|
17
|
+
|
18
|
+
@max_dist = opts[:max_fret_distance] || Fingering::DEFAULT_MAX_FRET_DISTANCE
|
19
|
+
|
20
|
+
get_png_data(fingerings.first)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def get_png_data(fingering)
|
26
|
+
rvg = Magick::RVG.new(5.cm, 5.cm).viewbox(0,0,270,250) do |canvas|
|
27
|
+
canvas.background_fill = 'white'
|
28
|
+
x_div = @fretboard.open_notes.size - 1
|
29
|
+
|
30
|
+
y_diff = 215 / (@max_dist + 1)
|
31
|
+
|
32
|
+
(@max_dist+2).times do |n|
|
33
|
+
canvas.line(20, n*y_diff+20, 250, n*y_diff+20)
|
34
|
+
end
|
35
|
+
|
36
|
+
@fretboard.open_notes.each_with_index do |note, i|
|
37
|
+
canvas.line(i*(230/x_div)+20, 20, i*(230/x_div)+20, 230)
|
38
|
+
|
39
|
+
unless [0,nil].include?(fingering[i])
|
40
|
+
canvas.circle(15, i*(230/x_div)+20,
|
41
|
+
fingering.relative(@max_dist)[i]*y_diff - 5)
|
42
|
+
end
|
43
|
+
|
44
|
+
canvas.text(i*(230/x_div)+20, 15) do |txt|
|
45
|
+
txt.tspan((fingering[i] || 'x').to_s).styles(
|
46
|
+
:text_anchor => 'middle',
|
47
|
+
:font_size => 20,
|
48
|
+
:font_family => 'helvetica',
|
49
|
+
:fill => 'black')
|
50
|
+
end
|
51
|
+
canvas.text(i*(230/x_div)+20, 249) do |txt|
|
52
|
+
txt.tspan(note.title).styles(:text_anchor => 'middle',
|
53
|
+
:font_size => 18,
|
54
|
+
:font_family => 'helvetica',
|
55
|
+
:fill => 'black')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
img = rvg.draw
|
61
|
+
img.format = 'PNG'
|
62
|
+
img.to_blob
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
# TODO: change pdf and png formatter to be
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chords
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 0.4.
|
9
|
+
- 2
|
10
|
+
version: 0.4.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Antti Hakala
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-08-
|
18
|
+
date: 2010-08-11 00:00:00 +03:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -39,6 +39,7 @@ files:
|
|
39
39
|
- lib/chords/html_formatter.rb
|
40
40
|
- lib/chords/note.rb
|
41
41
|
- lib/chords/pdf_formatter.rb
|
42
|
+
- lib/chords/png_formatter.rb
|
42
43
|
- lib/chords/text_formatter.rb
|
43
44
|
- lib/chords.rb
|
44
45
|
has_rdoc: true
|