lydown 0.3.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.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +357 -0
- data/bin/lydown +149 -0
- data/lib/lydown/core_ext.rb +121 -0
- data/lib/lydown/errors.rb +2 -0
- data/lib/lydown/lilypond.rb +41 -0
- data/lib/lydown/parsing/lydown.treetop +160 -0
- data/lib/lydown/parsing/nodes.rb +191 -0
- data/lib/lydown/parsing.rb +33 -0
- data/lib/lydown/rendering/base.rb +24 -0
- data/lib/lydown/rendering/comments.rb +7 -0
- data/lib/lydown/rendering/defaults.yml +185 -0
- data/lib/lydown/rendering/figures.rb +106 -0
- data/lib/lydown/rendering/lyrics.rb +14 -0
- data/lib/lydown/rendering/movement.rb +19 -0
- data/lib/lydown/rendering/music.rb +362 -0
- data/lib/lydown/rendering/settings.rb +107 -0
- data/lib/lydown/rendering/staff.rb +83 -0
- data/lib/lydown/rendering.rb +45 -0
- data/lib/lydown/templates/lilypond_doc.erb +15 -0
- data/lib/lydown/templates/movement.erb +48 -0
- data/lib/lydown/templates/part.erb +55 -0
- data/lib/lydown/templates.rb +22 -0
- data/lib/lydown/version.rb +3 -0
- data/lib/lydown/work.rb +192 -0
- data/lib/lydown.rb +11 -0
- metadata +84 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
<%
|
2
|
+
title = nil
|
3
|
+
if name && (name != '')
|
4
|
+
title = Lydown::Rendering.part_title(name)
|
5
|
+
end
|
6
|
+
id = "#{title && title.gsub(' ', '')}Staff"
|
7
|
+
|
8
|
+
score_mode = self['render_opts/mode'] == :score
|
9
|
+
|
10
|
+
clef = Lydown::Rendering::Staff.clef(name)
|
11
|
+
beaming_mode = Lydown::Rendering::Staff.beaming_mode(name)
|
12
|
+
partial = self[:pickup] ? "\\partial #{self[:pickup]}" : ""
|
13
|
+
|
14
|
+
end_barline = Lydown::Rendering::Staff.end_barline(self, movement)
|
15
|
+
|
16
|
+
cadenza = self[:time] == 'unmetered'
|
17
|
+
%>
|
18
|
+
|
19
|
+
<<
|
20
|
+
|
21
|
+
\new Staff = <%= id %> \with {
|
22
|
+
}
|
23
|
+
|
24
|
+
\context Staff = <%= id %> {
|
25
|
+
<% if score_mode %>\set Staff.instrumentName = #"<%= title %>"<% end %>
|
26
|
+
\relative c {
|
27
|
+
<% if clef %>
|
28
|
+
\clef "<%= clef %>"
|
29
|
+
<% end %>
|
30
|
+
<%= beaming_mode %>
|
31
|
+
<%= partial %>
|
32
|
+
<%= part['music'] %>
|
33
|
+
|
34
|
+
<% if end_barline %>
|
35
|
+
\bar "<%= end_barline %>"
|
36
|
+
<% end %>
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
<% if part['lyrics'] %>
|
41
|
+
\addlyrics {
|
42
|
+
<%= part['lyrics'] %>
|
43
|
+
}
|
44
|
+
<% end %>
|
45
|
+
|
46
|
+
<% if part['lyrics2'] %>
|
47
|
+
\addlyrics {
|
48
|
+
<%= part['lyrics2'] %>
|
49
|
+
}
|
50
|
+
<% end %>
|
51
|
+
|
52
|
+
<% if part['figures'] %>
|
53
|
+
\figures { <%= part['figures'] %> }
|
54
|
+
<% end %>
|
55
|
+
>>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Lydown
|
4
|
+
module Templates
|
5
|
+
TEMPLATES_DIR = File.join(File.dirname(__FILE__), 'templates')
|
6
|
+
|
7
|
+
@@templates = {}
|
8
|
+
|
9
|
+
def self.render(name, ctx, locals = {})
|
10
|
+
_binding = ctx.respond_to?(:template_binding) ? ctx.template_binding(locals) : binding
|
11
|
+
template(name).result(_binding)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.template(name)
|
15
|
+
@@templates[name] ||= load_template(name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.load_template(name)
|
19
|
+
ERB.new IO.read(File.join(TEMPLATES_DIR, "#{name}.erb")), 0, '<>'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/lydown/work.rb
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
require 'lydown/core_ext'
|
2
|
+
require 'lydown/templates'
|
3
|
+
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
module Lydown
|
7
|
+
# Work is a virtual lilypond document. It can contain multiple movements,
|
8
|
+
# and each movement can contain multiple parts. Each part can contain multiple
|
9
|
+
# streams: music, lyrics, figured bass.
|
10
|
+
#
|
11
|
+
# A Work instance is created in order to translate lydown code into a
|
12
|
+
# virtual lilypond document, and then render it. The actual rendering may
|
13
|
+
# include all of the streams in the document, or only a selection,such as a
|
14
|
+
# specific movement, a specific part, or a specific stream type.
|
15
|
+
class Work
|
16
|
+
attr_accessor :context
|
17
|
+
|
18
|
+
def initialize(opts = {})
|
19
|
+
@context = {}.deep!
|
20
|
+
reset_context(:work)
|
21
|
+
|
22
|
+
opts.each {|k, v| @context[k] = v}
|
23
|
+
|
24
|
+
process_work_files if opts[:path]
|
25
|
+
end
|
26
|
+
|
27
|
+
def reset_context(mode)
|
28
|
+
case mode
|
29
|
+
when :work, :movement
|
30
|
+
@context[:time] = '4/4'
|
31
|
+
@context[:cadenza_mode] = nil
|
32
|
+
@context[:key] = 'c major'
|
33
|
+
@context[:pickup] = nil
|
34
|
+
@context[:beaming] = nil
|
35
|
+
@context[:end_barline] = nil
|
36
|
+
@context[:part] = nil
|
37
|
+
@context['process/duration_values'] = ['4']
|
38
|
+
@context['process/running_values'] = []
|
39
|
+
@context['process/last_value'] = nil
|
40
|
+
@context['process/last_figures_value'] = nil
|
41
|
+
when :part
|
42
|
+
@context['process/duration_values'] = ['4']
|
43
|
+
@context['process/running_values'] = []
|
44
|
+
@context['process/last_value'] = nil
|
45
|
+
@context['process/last_figures_value'] = nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Used to bind to instance when rendering templates
|
50
|
+
def template_binding(locals = {})
|
51
|
+
b = binding
|
52
|
+
locals.each {|k, v| b.local_variable_set(k.to_sym, v)}
|
53
|
+
b
|
54
|
+
end
|
55
|
+
|
56
|
+
# translate a lydown stream into lilypond
|
57
|
+
def process(lydown_stream)
|
58
|
+
lydown_stream.each_with_index do |e, idx|
|
59
|
+
if e[:type]
|
60
|
+
Lydown::Rendering.translate(self, e, lydown_stream, idx)
|
61
|
+
else
|
62
|
+
raise LydownError, "Invalid lydown stream event: #{e.inspect}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def emit(stream_type, *content)
|
68
|
+
stream = current_stream(stream_type)
|
69
|
+
|
70
|
+
content.each {|c| stream << c}
|
71
|
+
end
|
72
|
+
|
73
|
+
def current_stream(type)
|
74
|
+
movement = @context[:movement]
|
75
|
+
part = @context[:part]
|
76
|
+
path = "movements/#{movement}/parts/#{part}/#{type}"
|
77
|
+
@context[path] ||= ''
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_lilypond(opts = {})
|
81
|
+
@context['render_opts'] = opts
|
82
|
+
ly_code = ''
|
83
|
+
|
84
|
+
if opts[:stream_path]
|
85
|
+
unless @context[opts[:stream_path]]
|
86
|
+
raise LydownError, "Invalid stream path #{opts[:stream_path].inspect}"
|
87
|
+
end
|
88
|
+
@context[opts[:stream_path]].strip
|
89
|
+
else
|
90
|
+
@original_context = @context
|
91
|
+
begin
|
92
|
+
@context = filter_context(opts)
|
93
|
+
Lydown::Templates.render(:lilypond_doc, self)
|
94
|
+
ensure
|
95
|
+
@context = @original_context
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def filter_context(opts = {})
|
101
|
+
filtered = @context.deep_clone
|
102
|
+
|
103
|
+
# delete default movement if other movements are present
|
104
|
+
if filtered['movements'].size > 1
|
105
|
+
filtered['movements'].delete('')
|
106
|
+
end
|
107
|
+
|
108
|
+
if opts[:movements]
|
109
|
+
opts[:movements] = [opts[:movements]] unless opts[:movements].is_a?(Array)
|
110
|
+
filtered['movements'].select! do |name, m|
|
111
|
+
opts[:movements].include?(name.to_s)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
if opts[:parts]
|
116
|
+
opts[:parts] = [opts[:parts]] unless opts[:parts].is_a?(Array)
|
117
|
+
end
|
118
|
+
filtered['movements'].each do |name, m|
|
119
|
+
# delete default part if other parts are present
|
120
|
+
if m['parts'].size > 1
|
121
|
+
m['parts'].delete('')
|
122
|
+
end
|
123
|
+
|
124
|
+
if opts[:parts]
|
125
|
+
m['parts'].select! do |pname, p|
|
126
|
+
opts[:parts].include?(pname.to_s)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
filtered
|
132
|
+
end
|
133
|
+
|
134
|
+
def compile(opts = {})
|
135
|
+
code = to_lilypond(opts)
|
136
|
+
|
137
|
+
Lydown::Lilypond.compile(code, opts)
|
138
|
+
end
|
139
|
+
|
140
|
+
def [](path)
|
141
|
+
context[path]
|
142
|
+
end
|
143
|
+
|
144
|
+
def []=(path, value)
|
145
|
+
context[path] = value
|
146
|
+
end
|
147
|
+
|
148
|
+
def process_work_files
|
149
|
+
path = @context[:path]
|
150
|
+
path += '.ld' if File.file?(path + '.ld')
|
151
|
+
|
152
|
+
if File.file?(path)
|
153
|
+
process_lydown_file(path)
|
154
|
+
elsif File.directory?(path)
|
155
|
+
process_directory(path)
|
156
|
+
else
|
157
|
+
raise LydownError, "Could not read #{path}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
DEFAULT_BASENAMES = %w{work movement}
|
162
|
+
|
163
|
+
def process_directory(path, recursive = true)
|
164
|
+
# process work code
|
165
|
+
process_lydown_file(File.join(path, 'work.ld'))
|
166
|
+
|
167
|
+
# process movement specific code
|
168
|
+
process_lydown_file(File.join(path, 'movement.ld'))
|
169
|
+
|
170
|
+
# Iterate over sorted directory entries
|
171
|
+
Dir["#{path}/*"].entries.sort.each do |entry|
|
172
|
+
if File.file?(entry) && (entry =~ /\.ld$/)
|
173
|
+
basename = File.basename(entry, '.*')
|
174
|
+
unless DEFAULT_BASENAMES.include?(basename)
|
175
|
+
part_code = [{type: :setting, key: 'part', value: basename}]
|
176
|
+
lydown_code = part_code + LydownParser.parse(IO.read(entry))
|
177
|
+
process(lydown_code)
|
178
|
+
end
|
179
|
+
elsif File.directory?(entry) && recursive
|
180
|
+
basename = File.basename(entry)
|
181
|
+
# set movement
|
182
|
+
process([{type: :setting, key: 'movement', value: basename}])
|
183
|
+
process_directory(entry, false)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def process_lydown_file(path)
|
189
|
+
process LydownParser.parse(IO.read(path)) if File.file?(path)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
data/lib/lydown.rb
ADDED
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lydown
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sharon Rosner
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: treetop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
description: 'Lydown '
|
28
|
+
email: ciconia@gmail.com
|
29
|
+
executables:
|
30
|
+
- lydown
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- LICENSE
|
35
|
+
- README.md
|
36
|
+
- bin/lydown
|
37
|
+
- lib/lydown.rb
|
38
|
+
- lib/lydown/core_ext.rb
|
39
|
+
- lib/lydown/errors.rb
|
40
|
+
- lib/lydown/lilypond.rb
|
41
|
+
- lib/lydown/parsing.rb
|
42
|
+
- lib/lydown/parsing/lydown.treetop
|
43
|
+
- lib/lydown/parsing/nodes.rb
|
44
|
+
- lib/lydown/rendering.rb
|
45
|
+
- lib/lydown/rendering/base.rb
|
46
|
+
- lib/lydown/rendering/comments.rb
|
47
|
+
- lib/lydown/rendering/defaults.yml
|
48
|
+
- lib/lydown/rendering/figures.rb
|
49
|
+
- lib/lydown/rendering/lyrics.rb
|
50
|
+
- lib/lydown/rendering/movement.rb
|
51
|
+
- lib/lydown/rendering/music.rb
|
52
|
+
- lib/lydown/rendering/settings.rb
|
53
|
+
- lib/lydown/rendering/staff.rb
|
54
|
+
- lib/lydown/templates.rb
|
55
|
+
- lib/lydown/templates/lilypond_doc.erb
|
56
|
+
- lib/lydown/templates/movement.erb
|
57
|
+
- lib/lydown/templates/part.erb
|
58
|
+
- lib/lydown/version.rb
|
59
|
+
- lib/lydown/work.rb
|
60
|
+
homepage: http://github.com/ciconia/lydown
|
61
|
+
licenses:
|
62
|
+
- MIT
|
63
|
+
metadata: {}
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
requirements: []
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 2.4.6
|
81
|
+
signing_key:
|
82
|
+
specification_version: 4
|
83
|
+
summary: Lydown is a language for music notation
|
84
|
+
test_files: []
|