chords 0.1 → 0.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/README CHANGED
@@ -2,9 +2,17 @@ Chords
2
2
  ======
3
3
  A chord generator lib for guitar-like instruments.
4
4
 
5
+ Using via gem (hosted at gemcutter.org)
6
+ ---------------------------------------
7
+
8
+ $ sudo gem install chords
9
+ $ chords -h
5
10
 
6
- Running irb under chords/lib:
7
11
 
12
+ Running irb under chords/lib:
13
+ -----------------------------
14
+ >> require 'rubygems'
15
+ => true
8
16
  >> require 'chords'
9
17
  => true
10
18
  >> include Chords
data/bin/chords CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'chords/command_line'
3
+ require 'chords/command_line_parser'
4
4
 
5
5
  Chords::CommandLineParser.new(ARGV).parse
@@ -6,47 +6,64 @@ module Chords
6
6
  attr_reader :notes
7
7
  attr_accessor :root
8
8
 
9
- def initialize(*notes)
9
+ def initialize(title_parts, *notes)
10
+ @title_parts = title_parts
10
11
  @notes = notes.flatten
11
12
  @root = @notes.first
12
13
  end
13
14
 
14
15
  def first_inversion
15
16
  raise "Not enough notes for inversion" if notes.size < 3
16
- inversion = Chord.new(@notes[1], @notes[2], @root, *@notes[3..-1])
17
+ inversion = Chord.new(@title_parts.dup + ['1st inv.'],
18
+ @notes[1], @notes[2], @root, *@notes[3..-1])
17
19
  inversion.root = @root
18
20
  inversion
19
21
  end
20
22
 
21
23
  def second_inversion
22
24
  raise "Not enough notes for inversion" if notes.size < 3
23
- inversion = Chord.new(@notes[2], @root, @notes[1], *@notes[3..-1])
25
+ inversion = Chord.new(@title_parts.dup + ['2nd inv.'],
26
+ @notes[2], @root, @notes[1], *@notes[3..-1])
24
27
  inversion.root = @root
25
28
  inversion
26
29
  end
27
30
 
28
31
  def sixth
29
- Chord.new(@notes + [@root + 9])
32
+ chord = Chord.new(@title_parts.dup + ['6th'], @notes + [@root + 9])
33
+ chord.root = @root
34
+ chord
30
35
  end
31
36
 
32
37
  def seventh
33
- Chord.new(@notes + [@root + 10])
38
+ chord = Chord.new(@title_parts.dup + ['7th'], @notes + [@root + 10])
39
+ chord.root = @root
40
+ chord
34
41
  end
35
42
 
36
43
  def add9
37
- Chord.new(@notes + [@root + 14])
44
+ chord = Chord.new(@title_parts.dup + ['add9'], @notes + [@root + 14])
45
+ chord.root = @root
46
+ chord
38
47
  end
39
48
 
40
49
  def add11
41
- Chord.new(@notes + [@root + 17])
50
+ chord = Chord.new(@title_parts.dup + ['add11'], @notes + [@root + 17])
51
+ chord.root = @root
52
+ chord
42
53
  end
43
54
 
44
55
  def bass(note)
45
- chord = Chord.new([note] + @notes)
46
- chord.root = self.root
56
+ chord = Chord.new(@title_parts.dup + ["(bass #{note.title})"], [note] + @notes)
57
+ chord.root = @root
47
58
  chord
48
59
  end
49
60
 
61
+ def title
62
+ ret = @root.title
63
+ ret += " #{@title_parts.join(' ')}" unless @title_parts.empty?
64
+ ret
65
+ end
66
+
50
67
  end
51
68
 
52
69
  end
@@ -16,7 +16,7 @@ module Chords
16
16
  raise "No chord with key #{key}" unless CHORDS.has_key?(key)
17
17
  notes = [root]
18
18
  notes += CHORDS[key].map{|interval| root + interval}
19
- Chord.new(notes)
19
+ Chord.new([key.to_s], notes)
20
20
  end
21
21
  end
22
22
 
@@ -10,6 +10,7 @@ module Chords
10
10
  @duplicates = 0
11
11
  @max_fret_distance = Chords::Fingering::DEFAULT_MAX_FRET_DISTANCE
12
12
  @tuning = Chords::Fretboard::TUNINGS[:standard]
13
+ @formatter = Chords::TextFormatter
13
14
  end
14
15
 
15
16
  def parse
@@ -48,6 +49,10 @@ module Chords
48
49
  @tuning = Chords::Fretboard::TUNINGS[t.to_sym]
49
50
  end
50
51
 
52
+ @opts.on("--pdf", "Output to pdf.") do
53
+ @formatter = Chords::PDFFormatter
54
+ end
55
+
51
56
  @opts.on_tail("-h", "--help", examples) do
52
57
  puts @opts
53
58
  end
@@ -67,10 +72,10 @@ module Chords
67
72
  chord_str =~ /^(.{1,2})\.(.*)/
68
73
 
69
74
  if $1 and $2 and Chords::NOTES.flatten.include?($1)
70
- note = Chords.const_get($1)
71
75
  begin
76
+ note = Chords.const_get($1)
72
77
  chord = note.class_eval($2)
73
- Fretboard.new(@tuning, @frets).print(chord,
78
+ Fretboard.new(@tuning, @frets, @formatter).print(chord,
74
79
  {:duplicates => @duplicates,
75
80
  :max_fret_distance => @max_fret_distance})
76
81
  return
@@ -87,6 +87,18 @@ module Chords
87
87
  @positions.hash
88
88
  end
89
89
 
90
+ # return an array of relative positions
91
+ def relative(max_fret_dist)
92
+ not_open = @positions.select{|p| !p.nil? and p > 0}
93
+
94
+ if not_open.max <= (max_fret_dist + 1)
95
+ @positions
96
+ else
97
+ diff = (not_open.min - 1)
98
+ @positions.map{|p| (p.nil? or p == 0) ? p : p - diff}
99
+ end
100
+ end
101
+
90
102
  private
91
103
 
92
104
  def new_note_positions(note, string_index, max_fret_distance)
@@ -1,6 +1,7 @@
1
1
  require 'chords/chord_factory'
2
2
  require 'chords/fingering'
3
3
  require 'chords/text_formatter'
4
+ require 'chords/pdf_formatter'
4
5
 
5
6
  module Chords
6
7
 
@@ -37,19 +38,25 @@ module Chords
37
38
  :c15 => [C.new(-1), G.new, D.new, G.new(1), C.new(1), D.new(1)],
38
39
 
39
40
  # "Extended chord" tunings
40
- :dmaj7 => [D.new(-1), A.new, D.new, Fs.new(1), A.new(1), Cs.new(1)]
41
+ :dmaj7 => [D.new(-1), A.new, D.new, Fs.new(1), A.new(1), Cs.new(1)],
42
+
43
+ # Other instruments
44
+ :mandolin => [G.new, D.new, A.new(1), E.new(2)],
45
+ :ukulele => [G.new, C.new, E.new(1), A.new(1)],
46
+ :banjo => [G.new, D.new, G.new(1), B.new(1), D.new(1)]
41
47
  }
42
48
 
43
49
  attr_reader :frets, :open_notes
44
50
 
45
- def initialize(open_notes, frets)
51
+ def initialize(open_notes, frets, formatter_class=TextFormatter)
46
52
  @open_notes, @frets = open_notes, frets
47
- @formatter = TextFormatter.new(self)
53
+ @formatter = formatter_class.new(self)
48
54
  end
49
55
 
50
56
  def self.method_missing(meth, *args)
51
57
  if TUNINGS.has_key?(meth)
52
- Fretboard.new(TUNINGS[meth], (args.first || DEFAULT_FRETS))
58
+ Fretboard.new(TUNINGS[meth], (args[0] || DEFAULT_FRETS),
59
+ args[1] || TextFormatter)
53
60
  else
54
61
  super
55
62
  end
@@ -61,7 +68,7 @@ module Chords
61
68
 
62
69
  def print(chord, opts={})
63
70
  fingerings = find(chord, opts)
64
- @formatter.print(fingerings)
71
+ @formatter.print(chord.title, fingerings, opts)
65
72
  end
66
73
 
67
74
  end
@@ -5,7 +5,7 @@ module Chords
5
5
 
6
6
  module Note
7
7
  include Comparable
8
- attr_reader :interval, :name, :octave
8
+ attr_reader :interval, :octave
9
9
 
10
10
  def self.create_by_value(value)
11
11
  octave = value / 12
@@ -33,14 +33,14 @@ module Chords
33
33
  end
34
34
  end
35
35
 
36
- def name; self.class.to_s.gsub(/^.*::/, '') end
37
-
36
+ def title; self.class.title end
37
+
38
38
  def +(other); Note.create_by_value(value + other) end
39
39
  def -(other); Note.create_by_value(value - other) end
40
40
  end
41
41
 
42
42
  # E.g. E + 3 => G
43
- module NoteClassArithmetic
43
+ module NoteClassMethods
44
44
  def +(interval)
45
45
  note = NOTES.detect{|n| [n].flatten.include?(self.to_s.gsub(/^.*::/, ''))}
46
46
  idx = NOTES.index(note) + interval
@@ -48,6 +48,7 @@ module Chords
48
48
  Chords.const_get [NOTES[idx]].flatten.first
49
49
  end
50
50
  def -(interval); self + (-interval) end
51
+ def title; self.to_s.gsub(/^.*::/, '').sub('s', '#') end
51
52
  end
52
53
 
53
54
  NOTES.each_with_index do |names, i|
@@ -55,7 +56,7 @@ module Chords
55
56
  names.each do |n|
56
57
  eval %Q(class #{n}
57
58
  include Note
58
- extend NoteClassArithmetic
59
+ extend NoteClassMethods
59
60
 
60
61
  def initialize(octave=0)
61
62
  @interval, @octave = #{i}, octave
@@ -0,0 +1,97 @@
1
+
2
+ require 'prawn'
3
+ require 'prawn/layout'
4
+
5
+ module Chords
6
+
7
+ class PDFFormatter
8
+
9
+ def initialize(fretboard)
10
+ @fretboard = fretboard
11
+ end
12
+
13
+ def print(title, fingerings, opts={})
14
+ @pdf = Prawn::Document.new(:top_margin => 50)
15
+ @pdf.draw_text "#{title}", :at => [@pdf.margin_box.left, @pdf.margin_box.top + 30]
16
+ @max_dist = opts[:max_fret_distance] || Fingering::DEFAULT_MAX_FRET_DISTANCE
17
+
18
+ if fingerings.empty?
19
+ @pdf.text 'No fingerings found.'
20
+ else
21
+ @pdf.define_grid(:columns => 4, :rows => 6, :gutter => 40)
22
+
23
+ fingerings.each_with_index do |f, i|
24
+ print_fingering(f, i)
25
+ end
26
+ end
27
+
28
+ @pdf.render_file('chords.pdf')
29
+ puts "Wrote chords.pdf"
30
+ end
31
+
32
+ private
33
+
34
+ def string_dist(box)
35
+ box.width / (@fretboard.open_notes.size - 1)
36
+ end
37
+
38
+ def fret_dist(box)
39
+ box.height / (@max_dist + 1)
40
+ end
41
+
42
+ def get_box(i)
43
+ @pdf.start_new_page if @pdf.page_count <= i / 24
44
+ i_on_page = i % 24
45
+ @pdf.grid(i_on_page / 4, i_on_page % 4)
46
+ end
47
+
48
+ def fretboard_text(str, x, y)
49
+ x_adj = str.length > 1 ? -6 : -3
50
+ @pdf.draw_text(str, :at => [x + x_adj, y])
51
+ end
52
+
53
+ def print_fretboard(i)
54
+ box = get_box(i)
55
+
56
+ @pdf.mask(:line_width) do
57
+ @pdf.line_width 3
58
+ @pdf.stroke_line box.top_left, box.top_right
59
+ end
60
+
61
+ @pdf.stroke_line box.bottom_left, box.bottom_right
62
+
63
+ @fretboard.open_notes.each_with_index do |note, note_i|
64
+ x = box.left + note_i*string_dist(box)
65
+ @pdf.stroke_line [x, box.top], [x, box.bottom]
66
+ fretboard_text(note.title, box.left + note_i*string_dist(box), box.bottom - 11)
67
+ end
68
+
69
+ @max_dist.times do |n|
70
+ y = box.top - ((n+1) * fret_dist(box))
71
+ @pdf.stroke_line [box.left, y], [box.right, y]
72
+ end
73
+ end
74
+
75
+ def print_fingering(fingering, i)
76
+ print_fretboard(i)
77
+
78
+ box = get_box(i)
79
+
80
+ rad = ([fret_dist(box), string_dist(box)].min / 2) - 4
81
+
82
+ fingering.each_with_index do |pos, pos_i|
83
+ fretboard_text((pos || 'x').to_s, box.left + pos_i*string_dist(box), box.top + 4)
84
+
85
+ next if [nil, 0].include?(pos)
86
+
87
+ @pdf.fill_and_stroke do
88
+ @pdf.circle_at [box.left + (pos_i * (string_dist(box))),
89
+ box.top + (fret_dist(box) / 2) -
90
+ (fingering.relative(@max_dist)[pos_i] * fret_dist(box))],
91
+ :radius => rad
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ end
@@ -7,7 +7,7 @@ module Chords
7
7
  @fretboard = fretboard
8
8
  end
9
9
 
10
- def print(fingerings)
10
+ def print(title, fingerings, opts={})
11
11
  rows = [""] * @fretboard.open_notes.size
12
12
 
13
13
  fingerings.each do |fingering|
@@ -20,7 +20,7 @@ module Chords
20
20
  while rows.first.length > idx
21
21
  parts = []
22
22
  rows.each_with_index do |row, i|
23
- parts << "#{@fretboard.open_notes[i].name.rjust(2, ' ')}: " + row[idx...(idx+75)]
23
+ parts << "#{@fretboard.open_notes[i].title.rjust(2, ' ')}: " + row[idx...(idx+75)]
24
24
  end
25
25
  puts "\n" + (parts.reverse.join("\n")) + "\n\n"
26
26
  idx += 75
metadata CHANGED
@@ -1,7 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chords
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.1"
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ version: "0.2"
5
9
  platform: ruby
6
10
  authors:
7
11
  - Antti Hakala
@@ -9,10 +13,23 @@ autorequire:
9
13
  bindir: bin
10
14
  cert_chain: []
11
15
 
12
- date: 2010-01-25 00:00:00 +02:00
16
+ date: 2010-03-31 00:00:00 +03:00
13
17
  default_executable:
14
- dependencies: []
15
-
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: prawn
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ segments:
27
+ - 0
28
+ - 8
29
+ - 4
30
+ version: 0.8.4
31
+ type: :runtime
32
+ version_requirements: *id001
16
33
  description: "Chords is a chord generator for guitar-like instruments. Handy for special tunings. "
17
34
  email: antti.hakala@gmail.com
18
35
  executables:
@@ -27,10 +44,11 @@ files:
27
44
  - bin/chords
28
45
  - lib/chords/chord.rb
29
46
  - lib/chords/chord_factory.rb
30
- - lib/chords/command_line.rb
47
+ - lib/chords/command_line_parser.rb
31
48
  - lib/chords/fingering.rb
32
49
  - lib/chords/fretboard.rb
33
50
  - lib/chords/note.rb
51
+ - lib/chords/pdf_formatter.rb
34
52
  - lib/chords/text_formatter.rb
35
53
  - lib/chords.rb
36
54
  has_rdoc: true
@@ -46,18 +64,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
46
64
  requirements:
47
65
  - - ">="
48
66
  - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
49
69
  version: "0"
50
- version:
51
70
  required_rubygems_version: !ruby/object:Gem::Requirement
52
71
  requirements:
53
72
  - - ">="
54
73
  - !ruby/object:Gem::Version
74
+ segments:
75
+ - 0
55
76
  version: "0"
56
- version:
57
77
  requirements: []
58
78
 
59
79
  rubyforge_project:
60
- rubygems_version: 1.3.5
80
+ rubygems_version: 1.3.6
61
81
  signing_key:
62
82
  specification_version: 3
63
83
  summary: Chord generator for guitar-like instruments.