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.
- data/.gitignore +4 -0
- data/Guardfile +8 -0
- data/README.markdown +214 -0
- data/bin/gitara +4 -0
- data/examples/aimee-man-wise-up/aimee-man-wise-up.ly +186 -0
- data/examples/aimee-man-wise-up/aimee-man-wise-up.midi +0 -0
- data/examples/aimee-man-wise-up/aimee-man-wise-up.pdf +0 -0
- data/examples/aimee-man-wise-up/aimee-man-wise-up.rb +170 -0
- data/examples/tab-with-bar.rb +7 -0
- data/examples/tab-with-reused-bar.rb +9 -0
- data/examples/tab.ly +117 -0
- data/examples/tab.rb +43 -0
- data/gitara.gemspec +15 -5
- data/lib/gitara.rb +38 -1
- data/lib/gitara/app.rb +29 -0
- data/lib/gitara/dsl.rb +35 -0
- data/lib/gitara/id_as_word.rb +8 -0
- data/lib/gitara/node/bar.rb +9 -0
- data/lib/gitara/node/bar/voiced_node.rb +13 -0
- data/lib/gitara/node/base.rb +82 -0
- data/lib/gitara/node/base/voiced_node.rb +22 -0
- data/lib/gitara/node/line.rb +6 -0
- data/lib/gitara/node/note_set.rb +6 -0
- data/lib/gitara/node/score.rb +6 -0
- data/lib/gitara/node/tab.rb +21 -0
- data/lib/gitara/pow/base.rb +11 -0
- data/lib/gitara/template/bar.erb +3 -0
- data/lib/gitara/template/line.erb +3 -0
- data/lib/gitara/template/score.erb +3 -0
- data/lib/gitara/template/tab.erb +91 -0
- data/lib/gitara/template/voice.erb +1 -0
- data/lib/gitara/version.rb +1 -1
- data/lib/gitara/voice.rb +20 -0
- data/spec/lib/gitara/app_spec.rb +12 -0
- data/spec/lib/gitara/dsl_spec.rb +173 -0
- data/spec/lib/gitara/node/bar/voiced_node_spec.rb +17 -0
- data/spec/lib/gitara/node/bar_spec.rb +22 -0
- data/spec/lib/gitara/node/base/voiced_node_spec.rb +35 -0
- data/spec/lib/gitara/node/base_spec.rb +201 -0
- data/spec/lib/gitara/node/note_set_spec.rb +4 -0
- data/spec/lib/gitara/node/tab_spec.rb +57 -0
- data/spec/lib/gitara/voice_spec.rb +31 -0
- data/spec/lib/gitara_spec.rb +23 -0
- data/spec/spec_helper.rb +27 -0
- metadata +217 -10
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 = "
|
12
|
-
s.description = "
|
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
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
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,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
|
+
|