chords 0.1 → 0.2

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