gitara 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +4 -0
  2. data/Guardfile +8 -0
  3. data/README.markdown +214 -0
  4. data/bin/gitara +4 -0
  5. data/examples/aimee-man-wise-up/aimee-man-wise-up.ly +186 -0
  6. data/examples/aimee-man-wise-up/aimee-man-wise-up.midi +0 -0
  7. data/examples/aimee-man-wise-up/aimee-man-wise-up.pdf +0 -0
  8. data/examples/aimee-man-wise-up/aimee-man-wise-up.rb +170 -0
  9. data/examples/tab-with-bar.rb +7 -0
  10. data/examples/tab-with-reused-bar.rb +9 -0
  11. data/examples/tab.ly +117 -0
  12. data/examples/tab.rb +43 -0
  13. data/gitara.gemspec +15 -5
  14. data/lib/gitara.rb +38 -1
  15. data/lib/gitara/app.rb +29 -0
  16. data/lib/gitara/dsl.rb +35 -0
  17. data/lib/gitara/id_as_word.rb +8 -0
  18. data/lib/gitara/node/bar.rb +9 -0
  19. data/lib/gitara/node/bar/voiced_node.rb +13 -0
  20. data/lib/gitara/node/base.rb +82 -0
  21. data/lib/gitara/node/base/voiced_node.rb +22 -0
  22. data/lib/gitara/node/line.rb +6 -0
  23. data/lib/gitara/node/note_set.rb +6 -0
  24. data/lib/gitara/node/score.rb +6 -0
  25. data/lib/gitara/node/tab.rb +21 -0
  26. data/lib/gitara/pow/base.rb +11 -0
  27. data/lib/gitara/template/bar.erb +3 -0
  28. data/lib/gitara/template/line.erb +3 -0
  29. data/lib/gitara/template/score.erb +3 -0
  30. data/lib/gitara/template/tab.erb +91 -0
  31. data/lib/gitara/template/voice.erb +1 -0
  32. data/lib/gitara/version.rb +1 -1
  33. data/lib/gitara/voice.rb +20 -0
  34. data/spec/lib/gitara/app_spec.rb +12 -0
  35. data/spec/lib/gitara/dsl_spec.rb +173 -0
  36. data/spec/lib/gitara/node/bar/voiced_node_spec.rb +17 -0
  37. data/spec/lib/gitara/node/bar_spec.rb +22 -0
  38. data/spec/lib/gitara/node/base/voiced_node_spec.rb +35 -0
  39. data/spec/lib/gitara/node/base_spec.rb +201 -0
  40. data/spec/lib/gitara/node/note_set_spec.rb +4 -0
  41. data/spec/lib/gitara/node/tab_spec.rb +57 -0
  42. data/spec/lib/gitara/voice_spec.rb +31 -0
  43. data/spec/lib/gitara_spec.rb +23 -0
  44. data/spec/spec_helper.rb +27 -0
  45. metadata +217 -10
@@ -0,0 +1,7 @@
1
+ Gitara.define do
2
+ bar "Intro" do
3
+ notes "<g'/1>8 <a/3>8 <g'/1>8 <a/3>16 <g'/1>8 <g/3>16 <e'/1>4 <g/3>8"
4
+ notes "<f/4>4 <f/4>4 <c/5>4 <e/4>4"
5
+ end
6
+ end
7
+
@@ -0,0 +1,9 @@
1
+ Gitara.define do
2
+ bar "Intro" do
3
+ notes "<g'/1>8 <a/3>8 <g'/1>8 <a/3>16 <g'/1>8 <g/3>16 <e'/1>4 <g/3>8"
4
+ notes "<f/4>4 <f/4>4 <c/5>4 <e/4>4"
5
+ end
6
+
7
+ bar "Intro"
8
+ end
9
+
data/examples/tab.ly ADDED
@@ -0,0 +1,117 @@
1
+ \version "2.12.3"
2
+ \include "english.ly"
3
+
4
+ %-----------------------------------------------------------------------
5
+ % Bars
6
+
7
+ vOneBarBeganIt = { \skip 4 <a\3 c'\2 >8 <g\3>8 \skip 4 <g\3 c'\2 >8 <g\3>8 }
8
+ vTwoBarBeganIt = { <f\4>4 <f\4>4 <c\5>4 <e\4>4 }
9
+
10
+ vOneBarItsNot = { r8 <g'\1>4 <a\3>16 <g'\1>8 <g\3>16 <e'\1>4 <g\3>16( <a\3>16) }
11
+ vTwoBarItsNot = { <f\4>4 <f\4>4 <c\5>4 <e\4>4 }
12
+
13
+ vOneBarItThough = { r8 <d'\2>16( <c'\2>16) r8 <a\3>16 <c'\2>16 r8 <d'\2>16( <c'\2>16) r8 <a\3>8 }
14
+ vTwoBarItThough = { <f\4>4 <f\4>4 <d\4>4 <d\4>4 }
15
+
16
+ vOneBarWhatYouThought = { r8 <g'\1>4 <a\3>16 <g'\1>8 <g\3>16 <e'\1>4 <g\3>8 }
17
+ vTwoBarWhatYouThought = { <f\4>4 <f\4>4 <c\5>4 <e\4>4 }
18
+
19
+ vOneBarWhenYouFirst = { <e'\1>8 <d'\2>16( <c'\2>8) <a\3>8. <c'\2>4 <a\3>8 <c'\2>8 }
20
+ vTwoBarWhenYouFirst = { <a,\5>4 <a,\5>8 <e\4>4 <a,\5>4 \skip 8 }
21
+
22
+ vOneBarYouGot = { <g'\1>8 <a\3>8 <g'\1>8 <a\3>16 <g'\1>8 <g\3>16 <e'\1>4 <g\3>16( <a\3>16) }
23
+ vTwoBarYouGot = { <f\4>4 <f\4>4 <c\5>4 <e\4>4 }
24
+
25
+
26
+ %-----------------------------------------------------------------------
27
+ % Lines
28
+
29
+ vOneLineVerseOneLineTwo = { \vOneBarYouGot \vOneBarWhatYouThought \vOneBarWhenYouFirst \vOneBarItThough \break }
30
+ vTwoLineVerseOneLineTwo = { \vTwoBarYouGot \vTwoBarWhatYouThought \vTwoBarWhenYouFirst \vTwoBarItThough \break }
31
+
32
+ vOneLineTabOneScoreEightLineOne = { \vOneBarItsNot \vOneBarWhatYouThought \vOneBarWhenYouFirst \vOneBarBeganIt \break }
33
+ vTwoLineTabOneScoreEightLineOne = { \vTwoBarItsNot \vTwoBarWhatYouThought \vTwoBarWhenYouFirst \vTwoBarBeganIt \break }
34
+
35
+
36
+ %-----------------------------------------------------------------------
37
+ % Scores
38
+
39
+ vOneScoreTabOneScoreEight = { \vOneLineTabOneScoreEightLineOne \vOneLineVerseOneLineTwo }
40
+ vTwoScoreTabOneScoreEight = { \vTwoLineTabOneScoreEightLineOne \vTwoLineVerseOneLineTwo }
41
+
42
+
43
+ %-----------------------------------------------------------------------
44
+ % Voices
45
+
46
+ vOne = { \vOneScoreTabOneScoreEight }
47
+
48
+ vTwo = { \vTwoScoreTabOneScoreEight }
49
+
50
+
51
+ \score {
52
+ \new StaffGroup <<
53
+ \new Staff <<
54
+ \tempo 4 = 75
55
+ \clef "treble_8"
56
+
57
+ \new Voice {
58
+ \voiceOne
59
+ \vOne
60
+ }
61
+ \new Voice {
62
+ \voiceTwo
63
+ \vTwo
64
+ }
65
+ >>
66
+
67
+ \new TabStaff <<
68
+ \new TabVoice {
69
+ \slurUp
70
+ \vOne
71
+ }
72
+ \new TabVoice {
73
+ \slurUp
74
+ \vTwo
75
+ }
76
+ >>
77
+ >>
78
+
79
+ \layout {
80
+ \context { \Staff
81
+ \override TimeSignature #'style = #'numbered
82
+ \override StringNumber #'transparent = ##t
83
+ }
84
+ \context { \TabStaff
85
+ \override TimeSignature #'style = #'numbered
86
+ }
87
+ \context { \Voice
88
+ \remove Slur_engraver
89
+ }
90
+ \context { \TabVoice
91
+ \remove Dots_engraver
92
+ \remove Stem_engraver
93
+ \remove Rest_engraver
94
+ }
95
+ }
96
+ }
97
+
98
+ % showLastLength = R1*4
99
+ \score {
100
+ \new Staff \with {midiInstrument = #"acoustic guitar (nylon)"} <<
101
+ \tempo 4 = 75
102
+ \clef "treble_8"
103
+
104
+ \new Voice {
105
+ \unfoldRepeats {
106
+ \vOne
107
+ }
108
+ }
109
+ \new Voice {
110
+ \unfoldRepeats {
111
+ \vTwo
112
+ }
113
+ }
114
+ >>
115
+
116
+ \midi {}
117
+ }
data/examples/tab.rb ADDED
@@ -0,0 +1,43 @@
1
+ Gitara.define do
2
+ bar :BeganIt do
3
+ notes "/skip 4 <a/3 c'/2 >8 <g/3>8 /skip 4 <g/3 c'/2 >8 <g/3>8"
4
+ notes "<f/4>4 <f/4>4 <c/5>4 <e/4>4"
5
+ end
6
+
7
+ bar :ItsNot do
8
+ notes "r8 <g'/1>4 <a/3>16 <g'/1>8 <g/3>16 <e'/1>4 <g/3>16( <a/3>16)"
9
+ notes "<f/4>4 <f/4>4 <c/5>4 <e/4>4"
10
+ end
11
+
12
+ bar :ItThough do
13
+ notes "r8 <d'/2>16( <c'/2>16) r8 <a/3>16 <c'/2>16 r8 <d'/2>16( <c'/2>16) r8 <a/3>8"
14
+ notes "<f/4>4 <f/4>4 <d/4>4 <d/4>4"
15
+ end
16
+
17
+ bar :WhatYouThought do
18
+ notes "r8 <g'/1>4 <a/3>16 <g'/1>8 <g/3>16 <e'/1>4 <g/3>8"
19
+ notes "<f/4>4 <f/4>4 <c/5>4 <e/4>4"
20
+ end
21
+
22
+ bar :WhenYouFirst do
23
+ notes "<e'/1>8 <d'/2>16( <c'/2>8) <a/3>8. <c'/2>4 <a/3>8 <c'/2>8"
24
+ notes "<a,/5>4 <a,/5>8 <e/4>4 <a,/5>4 /skip 8"
25
+ end
26
+
27
+ bar :YouGot do
28
+ notes "<g'/1>8 <a/3>8 <g'/1>8 <a/3>16 <g'/1>8 <g/3>16 <e'/1>4 <g/3>16( <a/3>16)"
29
+ notes "<f/4>4 <f/4>4 <c/5>4 <e/4>4"
30
+ end
31
+
32
+ line :VerseOneLineTwo do
33
+ bar :YouGot, :WhatYouThought, :WhenYouFirst, :ItThough
34
+ end
35
+
36
+ score do
37
+ line do
38
+ bar :ItsNot, :WhatYouThought, :WhenYouFirst, :BeganIt
39
+ end
40
+
41
+ line :VerseOneLineTwo
42
+ end
43
+ end
data/gitara.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
8
8
  s.authors = ["George Mendoza"]
9
9
  s.email = ["gsmendoza@gmail.com"]
10
10
  s.homepage = ""
11
- s.summary = "A Ruby DSL for tablatures"
12
- s.description = "This will be a work in progress. Ultimately the goal is to have a good basic tablature DSL that is easily convertible to lilypond."
11
+ s.summary = "Ruby + Lilypond = pretty guitar tablatures."
12
+ s.description = "A Ruby DSL for generating Lilypond guitar tablatures."
13
13
 
14
14
  s.rubyforge_project = "gitara"
15
15
 
@@ -18,7 +18,17 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- # specify any dependencies here; for example:
22
- # s.add_development_dependency "rspec"
23
- # s.add_runtime_dependency "rest-client"
21
+ s.add_runtime_dependency "active_support"
22
+ s.add_runtime_dependency "erubis"
23
+ s.add_runtime_dependency "linguistics"
24
+ s.add_runtime_dependency "parslet"
25
+ s.add_runtime_dependency "pow"
26
+ s.add_runtime_dependency "thor"
27
+ s.add_runtime_dependency "valuable"
28
+
29
+ s.add_development_dependency "guard"
30
+ s.add_development_dependency "guard-rspec"
31
+ s.add_development_dependency "pry"
32
+ s.add_development_dependency "rb-inotify"
33
+ s.add_development_dependency "rspec"
24
34
  end
data/lib/gitara.rb CHANGED
@@ -1,5 +1,42 @@
1
+ require "active_support/inflector"
2
+ require "erubis"
3
+ require "linguistics"
4
+ require "parslet"
5
+ require "pow"
6
+ require "thor"
7
+ require "valuable"
8
+
9
+ require "gitara/app"
10
+ require "gitara/dsl"
11
+ require "gitara/id_as_word"
12
+ require "gitara/node/base"
13
+ require "gitara/node/base/voiced_node"
14
+ require "gitara/node/bar"
15
+ require "gitara/node/bar/voiced_node"
16
+ require "gitara/node/line"
17
+ require "gitara/node/note_set"
18
+ require "gitara/node/score"
19
+ require "gitara/node/tab"
20
+ require "gitara/pow/base"
1
21
  require "gitara/version"
22
+ require "gitara/voice"
23
+
24
+ Linguistics::use :en
2
25
 
3
26
  module Gitara
4
- # Your code goes here...
27
+ def self.define(&block)
28
+ @tab = Dsl.new(:node => Node::Tab.new).tap {|dsl|
29
+ dsl.instance_eval(&block) if block_given?
30
+ }.node
31
+ end
32
+
33
+ def self.render(path, object)
34
+ template = (Pow!('gitara/template') / "#{path}.erb")
35
+ erb = Erubis::Eruby.new(template.read!)
36
+ erb.evaluate(object)
37
+ end
38
+
39
+ def self.tab
40
+ @tab
41
+ end
5
42
  end
data/lib/gitara/app.rb ADDED
@@ -0,0 +1,29 @@
1
+ module Gitara
2
+ class App < Thor
3
+ desc "export PATH [OPTIONS]...", "Export PATH to lilypond and friends."
4
+
5
+ method_option "target-directory",
6
+ :aliases => "-t",
7
+ :default => '.',
8
+ :desc => "Export files to TARGET-DIRECTORY",
9
+ :type => :string
10
+
11
+ method_option "run-lilypond",
12
+ :aliases => "-l",
13
+ :default => true,
14
+ :desc => "Run lilypond program after generating lilypond file", :default => true,
15
+ :type => :boolean
16
+
17
+ def export(source_path)
18
+ load source_path
19
+ tab = Gitara.tab
20
+ lilypond_name = Pow(source_path).name(false) + '.ly'
21
+ lilypond_path = Pow(options['target-directory']) / lilypond_name
22
+ lilypond_path.write(Gitara.render('tab', tab))
23
+
24
+ if options['run-lilypond']
25
+ `lilypond -o #{lilypond_path.parent / lilypond_path.name(false)} #{lilypond_path}`
26
+ end
27
+ end
28
+ end
29
+ end
data/lib/gitara/dsl.rb ADDED
@@ -0,0 +1,35 @@
1
+ module Gitara
2
+ class Dsl < Valuable
3
+ has_value :node
4
+
5
+ def add(child, &block)
6
+ self.node.add child
7
+ Dsl.new(:node => child).instance_eval(&block) if block_given?
8
+ end
9
+
10
+ def add_names(options = {}, &block)
11
+ names = options[:names].empty? ? [nil] : options[:names]
12
+ node_class = options[:node_class]
13
+
14
+ names.map{|name| node_class.new(:name => name) }.each do |child|
15
+ add child, &block
16
+ end
17
+ end
18
+
19
+ def bar(*names, &block)
20
+ add_names :names => names, :node_class => Node::Bar, &block
21
+ end
22
+
23
+ def line(*names, &block)
24
+ add_names :names => names, :node_class => Node::Line, &block
25
+ end
26
+
27
+ def notes(value)
28
+ add Node::NoteSet.new(:value => value)
29
+ end
30
+
31
+ def score(*names, &block)
32
+ add_names :names => names, :node_class => Node::Score, &block
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,8 @@
1
+ module Gitara
2
+ module IdAsWord
3
+ def id_as_word
4
+ id.en.numwords.gsub('-', '_').camelize
5
+ end
6
+ end
7
+ end
8
+
@@ -0,0 +1,9 @@
1
+ module Gitara
2
+ module Node
3
+ class Bar < Base
4
+ def note_sets
5
+ children.select{|child| child.is_a?(Node::NoteSet)}
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module Gitara
2
+ module Node
3
+ class Bar
4
+ class VoicedNode < Base::VoicedNode
5
+ alias_method :bar, :node
6
+
7
+ def matching_note_set
8
+ bar.note_sets[voice.id - 1]
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,82 @@
1
+ module Gitara
2
+ module Node
3
+ class Base < Valuable
4
+ include IdAsWord
5
+
6
+ has_value :name
7
+ has_value :id, :default => 1
8
+ has_value :parent
9
+ has_value :value
10
+
11
+ def add(child)
12
+ own_children << child
13
+ child.id = own_children.size
14
+ child.parent = self
15
+ end
16
+
17
+ def children
18
+ if own_children.empty?
19
+ definition ? definition.own_children : []
20
+ else
21
+ own_children
22
+ end
23
+ end
24
+
25
+ def children=(values)
26
+ values.each do |child|
27
+ add child
28
+ end
29
+ end
30
+
31
+ def definition?
32
+ ! own_children.empty?
33
+ end
34
+
35
+ def definition_of?(target)
36
+ self.definition? && self.name == target.name && self.class == target.class
37
+ end
38
+
39
+ def definitions(klass)
40
+ self.is_a?(klass) && self.definition? ? [self] : self.own_children.map{|child| child.definitions(klass) }.flatten
41
+ end
42
+
43
+ def name
44
+ attributes[:name] || "#{parent && parent.name}#{self.class.to_s.split('::').last}#{self.id_as_word}"
45
+ end
46
+
47
+ def own_children
48
+ @children ||= []
49
+ end
50
+
51
+ def root
52
+ parent.nil? ? self : parent.root
53
+ end
54
+
55
+ def value
56
+ attributes[:value].gsub('/', "\\")
57
+ end
58
+
59
+ def voiced_as(arg)
60
+ if arg.is_a?(Voice)
61
+ self.class::VoicedNode.new(:node => self, :voice => arg)
62
+ elsif arg.is_a?(Array)
63
+ arg.map{|voice| self.voiced_as(voice) }
64
+ else
65
+ raise ArgumentError
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def definition(target = self)
72
+ if self.definition_of?(target)
73
+ self
74
+ else
75
+ result = parent.own_children.detect{|node| node.definition_of?(target) }
76
+ result ? result : parent.definition(target)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+