gitara 0.0.1 → 0.1.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.
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
+