lydown 0.12.4 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +41 -1
- data/bin/lydown +2 -0
- data/lib/lydown.rb +6 -2
- data/lib/lydown/cache.rb +5 -1
- data/lib/lydown/cli.rb +1 -1
- data/lib/lydown/cli/commands.rb +7 -11
- data/lib/lydown/cli/compiler.rb +5 -0
- data/lib/lydown/cli/proofing.rb +2 -2
- data/lib/lydown/cli/repl.rb +1 -1
- data/lib/lydown/cli/support.rb +0 -33
- data/lib/lydown/defaults.yml +50 -8
- data/lib/lydown/inverso.rb +84 -0
- data/lib/lydown/lilypond.rb +76 -10
- data/lib/lydown/ly_lib/lib.ly +140 -127
- data/lib/lydown/parsing/lydown.treetop +25 -12
- data/lib/lydown/parsing/nodes.rb +55 -19
- data/lib/lydown/rendering.rb +72 -1
- data/lib/lydown/rendering/base.rb +21 -0
- data/lib/lydown/rendering/command.rb +53 -0
- data/lib/lydown/rendering/layout.rb +83 -0
- data/lib/lydown/rendering/lyrics.rb +1 -1
- data/lib/lydown/rendering/markup.rb +23 -0
- data/lib/lydown/rendering/movement.rb +7 -4
- data/lib/lydown/rendering/music.rb +35 -29
- data/lib/lydown/rendering/notes.rb +75 -41
- data/lib/lydown/rendering/repeats.rb +27 -0
- data/lib/lydown/rendering/settings.rb +36 -9
- data/lib/lydown/rendering/skipping.rb +10 -2
- data/lib/lydown/rendering/staff.rb +38 -31
- data/lib/lydown/rendering/voices.rb +1 -1
- data/lib/lydown/templates.rb +8 -8
- data/lib/lydown/templates/layout.rb +40 -0
- data/lib/lydown/templates/lilypond_doc.rb +95 -0
- data/lib/lydown/templates/movement.rb +188 -0
- data/lib/lydown/templates/multi_voice.rb +25 -0
- data/lib/lydown/templates/part.rb +146 -0
- data/lib/lydown/templates/variables.rb +43 -0
- data/lib/lydown/translation/ripple.rb +1 -1
- data/lib/lydown/translation/ripple/nodes.rb +51 -2
- data/lib/lydown/translation/ripple/ripple.treetop +87 -10
- data/lib/lydown/version.rb +1 -1
- data/lib/lydown/work.rb +19 -2
- data/lib/lydown/work_context.rb +10 -2
- metadata +12 -8
- data/lib/lydown/cli/installer.rb +0 -175
- data/lib/lydown/templates/lilypond_doc.erb +0 -34
- data/lib/lydown/templates/movement.erb +0 -118
- data/lib/lydown/templates/multi_voice.erb +0 -16
- data/lib/lydown/templates/part.erb +0 -118
- data/lib/lydown/templates/variables.erb +0 -43
@@ -34,7 +34,7 @@ grammar Lydown
|
|
34
34
|
comment? <Setting>
|
35
35
|
end
|
36
36
|
rule setting_key
|
37
|
-
[a-z0-9_]+ <Setting::Key>
|
37
|
+
[a-z0-9_\-]+ <Setting::Key>
|
38
38
|
end
|
39
39
|
rule setting_value
|
40
40
|
(!"\n" !"//" .)* <Setting::Value>
|
@@ -46,27 +46,31 @@ grammar Lydown
|
|
46
46
|
[ \t]+
|
47
47
|
end
|
48
48
|
rule event
|
49
|
-
(inline_command / inline_lyrics / voice_selector /
|
50
|
-
|
49
|
+
(inline_command / inline_lyrics / voice_selector / repeat_start / volta /
|
50
|
+
repeat_end / barline / source_ref /
|
51
|
+
duration / standalone_figures / chord / note / rest /
|
51
52
|
silence / phrasing / tie) white_space*
|
52
53
|
end
|
54
|
+
rule repeat_start
|
55
|
+
'|:*' [0-9]+ <Repeat::Start>
|
56
|
+
end
|
57
|
+
rule volta
|
58
|
+
'|*' <Repeat::Volta>
|
59
|
+
end
|
60
|
+
rule repeat_end
|
61
|
+
'*|' <Repeat::End>
|
62
|
+
end
|
53
63
|
rule barline
|
54
|
-
('?|' / ':|][|:' / '[|:' / ':|]' / [\|\.\:]+) <Barline>
|
64
|
+
('?|' / ':|][|:' / '[|:' / ':|]' / [\|\.\:']+) <Barline>
|
55
65
|
end
|
56
66
|
rule duration
|
57
67
|
tuplet_value / duration_value / duration_macro
|
58
68
|
end
|
59
|
-
rule grace_duration
|
60
|
-
'$' grace_duration_type* number <GraceDuration>
|
61
|
-
end
|
62
|
-
rule grace_duration_type
|
63
|
-
[\/\^]
|
64
|
-
end
|
65
69
|
rule tuplet_value
|
66
70
|
number '%' (number '/' number)? <TupletValue>
|
67
71
|
end
|
68
72
|
rule duration_value
|
69
|
-
duration_number dots* multiplier? <DurationValue>
|
73
|
+
duration_number dots* cross_bar_dotting? multiplier? grace? <DurationValue>
|
70
74
|
end
|
71
75
|
rule duration_number
|
72
76
|
[0-9]+ / 'l'
|
@@ -77,9 +81,15 @@ grammar Lydown
|
|
77
81
|
rule dots
|
78
82
|
'.'+
|
79
83
|
end
|
84
|
+
rule cross_bar_dotting
|
85
|
+
'!'
|
86
|
+
end
|
80
87
|
rule multiplier
|
81
88
|
'*' number ('/' number)*
|
82
89
|
end
|
90
|
+
rule grace
|
91
|
+
[°^`]
|
92
|
+
end
|
83
93
|
rule duration_macro
|
84
94
|
'{' duration_macro__expression '}'
|
85
95
|
end
|
@@ -194,7 +204,10 @@ grammar Lydown
|
|
194
204
|
[\<\>\|\\]? [a-zA-Z_\-\.0-9]+ <Command::Key>
|
195
205
|
end
|
196
206
|
rule inline_command_argument
|
197
|
-
(string / [^\s\t\n\:]+) <Command::Argument>
|
207
|
+
(string / parenthesized_command_argument / [^\s\t\n\:]+)+ <Command::Argument>
|
208
|
+
end
|
209
|
+
rule parenthesized_command_argument
|
210
|
+
'(' (parenthesized_command_argument / [^\)]+) ')'
|
198
211
|
end
|
199
212
|
rule voice_selector
|
200
213
|
[1234u] ':' <VoiceSelector>
|
data/lib/lydown/parsing/nodes.rb
CHANGED
@@ -103,10 +103,31 @@ module Lydown::Parsing
|
|
103
103
|
end
|
104
104
|
|
105
105
|
class DurationValue < Root
|
106
|
+
GRACE_KIND = {
|
107
|
+
'°' => :grace,
|
108
|
+
'`' => :acciaccatura,
|
109
|
+
'^' => :appoggiatura
|
110
|
+
}
|
111
|
+
|
106
112
|
def to_stream(stream, opts)
|
107
|
-
|
108
|
-
|
109
|
-
|
113
|
+
if text_value.strip =~ /^(.+)([°`^])$/
|
114
|
+
event = {
|
115
|
+
type: :grace,
|
116
|
+
value: $1,
|
117
|
+
kind: GRACE_KIND[$2]
|
118
|
+
}
|
119
|
+
else
|
120
|
+
event = {
|
121
|
+
type: :duration,
|
122
|
+
value: text_value.strip
|
123
|
+
}
|
124
|
+
if event[:value] =~ /\!/
|
125
|
+
event[:value].gsub!('!', '')
|
126
|
+
event[:cross_bar_dotting] = true
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
stream << event_hash(stream, opts, event)
|
110
131
|
end
|
111
132
|
end
|
112
133
|
|
@@ -129,22 +150,6 @@ module Lydown::Parsing
|
|
129
150
|
end
|
130
151
|
end
|
131
152
|
|
132
|
-
class GraceDuration < Root
|
133
|
-
GRACE_KIND = {
|
134
|
-
nil => :grace,
|
135
|
-
'/' => :acciaccatura,
|
136
|
-
'^' => :appoggiatura
|
137
|
-
}
|
138
|
-
|
139
|
-
def to_stream(stream, opts)
|
140
|
-
if text_value =~ /^\$([\/\^])?(\d+)$/
|
141
|
-
stream << event_hash(stream, opts, {
|
142
|
-
type: :grace, value: $2, kind: GRACE_KIND[$1]
|
143
|
-
})
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
153
|
class Note < Root
|
149
154
|
def to_stream(stream, opts)
|
150
155
|
note = event_hash(stream, opts, {
|
@@ -413,4 +418,35 @@ module Lydown::Parsing
|
|
413
418
|
end
|
414
419
|
end
|
415
420
|
end
|
421
|
+
|
422
|
+
module Repeat
|
423
|
+
class Start < Root
|
424
|
+
def to_stream(stream, opts)
|
425
|
+
ref = {type: :repeat_start, raw: text_value, count: 2}
|
426
|
+
if text_value =~ /(\d+)$/
|
427
|
+
ref[:count] = $1.to_i
|
428
|
+
end
|
429
|
+
|
430
|
+
stream << event_hash(stream, opts, ref)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
class Volta < Root
|
435
|
+
def to_stream(stream, opts)
|
436
|
+
stream << event_hash(stream, opts, {
|
437
|
+
type: :repeat_volta,
|
438
|
+
raw: text_value
|
439
|
+
})
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
class End < Root
|
444
|
+
def to_stream(stream, opts)
|
445
|
+
stream << event_hash(stream, opts, {
|
446
|
+
type: :repeat_end,
|
447
|
+
raw: text_value
|
448
|
+
})
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|
416
452
|
end
|
data/lib/lydown/rendering.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'lydown/templates'
|
2
|
+
require 'lydown/inverso'
|
2
3
|
require 'lydown/work'
|
3
4
|
require 'lydown/rendering/base'
|
4
5
|
require 'lydown/rendering/literal'
|
@@ -6,6 +7,7 @@ require 'lydown/rendering/comments'
|
|
6
7
|
require 'lydown/rendering/lyrics'
|
7
8
|
require 'lydown/rendering/notes'
|
8
9
|
require 'lydown/rendering/music'
|
10
|
+
require 'lydown/rendering/repeats'
|
9
11
|
require 'lydown/rendering/settings'
|
10
12
|
require 'lydown/rendering/staff'
|
11
13
|
require 'lydown/rendering/movement'
|
@@ -13,6 +15,8 @@ require 'lydown/rendering/command'
|
|
13
15
|
require 'lydown/rendering/voices'
|
14
16
|
require 'lydown/rendering/source_ref'
|
15
17
|
require 'lydown/rendering/skipping'
|
18
|
+
require 'lydown/rendering/layout'
|
19
|
+
require 'lydown/rendering/markup'
|
16
20
|
|
17
21
|
module Lydown::Rendering
|
18
22
|
class << self
|
@@ -70,6 +74,10 @@ module Lydown::Rendering
|
|
70
74
|
end
|
71
75
|
|
72
76
|
def include_files(context, opts)
|
77
|
+
if context.render_mode == :part
|
78
|
+
opts = opts.merge(part: context['render_opts/parts'])
|
79
|
+
end
|
80
|
+
|
73
81
|
filenames = []
|
74
82
|
if opts.has_key?(:movement)
|
75
83
|
add_includes(filenames, context, :includes, opts)
|
@@ -93,9 +101,72 @@ module Lydown::Rendering
|
|
93
101
|
when '.ely'
|
94
102
|
Lydown::Templates.render(fn, context)
|
95
103
|
else
|
96
|
-
"\\include \"#{fn}\""
|
104
|
+
"\\include \"#{File.expand_path(fn)}\""
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def add_requires(packages, context, key, opts)
|
110
|
+
requires = context.get_setting(key, opts)
|
111
|
+
packages.concat(requires) if requires
|
112
|
+
end
|
113
|
+
|
114
|
+
def packages_to_load(context, opts)
|
115
|
+
packages = []
|
116
|
+
if opts.has_key?(:movement)
|
117
|
+
add_requires(packages, context, :requires, opts)
|
118
|
+
case context.render_mode
|
119
|
+
when :score
|
120
|
+
add_requires(packages, context, 'score/requires', opts)
|
121
|
+
when :part
|
122
|
+
add_requires(packages, context, 'parts/requires', opts)
|
123
|
+
if opts[:part]
|
124
|
+
add_requires(packages, context, "parts/#{opts[:part]}/requires", opts)
|
125
|
+
end
|
97
126
|
end
|
127
|
+
else
|
128
|
+
# paths to be included at top of lilypond doc should be defined under
|
129
|
+
# document/requires
|
130
|
+
add_requires(packages, context, 'document/requires', opts)
|
98
131
|
end
|
132
|
+
|
133
|
+
packages.uniq
|
134
|
+
end
|
135
|
+
|
136
|
+
def layout_info(context, opts = {})
|
137
|
+
layout = (context.get_merged_setting_tree(:layout, opts) || {}).deep!
|
138
|
+
|
139
|
+
case context.render_mode
|
140
|
+
when :score
|
141
|
+
layout.deep_merge!(context.get_merged_setting_tree('score/layout', opts) || {})
|
142
|
+
when :part
|
143
|
+
layout.deep_merge!(context.get_merged_setting_tree('parts/layout', opts) || {})
|
144
|
+
layout.deep_merge!(context.get_merged_setting_tree("parts/#{context['render_opts/parts']}/layout", opts) || {})
|
145
|
+
end
|
146
|
+
|
147
|
+
layout
|
148
|
+
end
|
149
|
+
|
150
|
+
def get_set_variables(context, opts = {})
|
151
|
+
set = (context.get_merged_setting_tree(:set, opts) || {}).deep!
|
152
|
+
|
153
|
+
case context.render_mode
|
154
|
+
when :score
|
155
|
+
set.deep_merge!(context.get_merged_setting_tree('score/set', opts) || {})
|
156
|
+
when :part
|
157
|
+
set.deep_merge!(context.get_merged_setting_tree('parts/set', opts) || {})
|
158
|
+
set.deep_merge!(context.get_merged_setting_tree("parts/#{context['render_opts/parts']}/set", opts) || {})
|
159
|
+
end
|
160
|
+
|
161
|
+
set
|
162
|
+
end
|
163
|
+
|
164
|
+
def lyrics_markup(context, opts = {})
|
165
|
+
if context.render_mode == :part
|
166
|
+
opts = opts.merge(part: context['render_opts/parts'])
|
167
|
+
end
|
168
|
+
|
169
|
+
context.get_setting('lyrics_markup', opts)
|
99
170
|
end
|
100
171
|
end
|
101
172
|
end
|
@@ -11,6 +11,27 @@ module Lydown::Rendering
|
|
11
11
|
# do nothing by default
|
12
12
|
end
|
13
13
|
|
14
|
+
def prev_event
|
15
|
+
idx = @idx - 1
|
16
|
+
while idx >= 0
|
17
|
+
e = @stream[idx]
|
18
|
+
return e if e && e[:type] != :comment
|
19
|
+
idx -= 1
|
20
|
+
end
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_prev_event(filter)
|
25
|
+
prev = prev_event
|
26
|
+
return nil unless prev
|
27
|
+
|
28
|
+
filter.each do |k, v|
|
29
|
+
return nil unless prev[k] == v
|
30
|
+
end
|
31
|
+
|
32
|
+
prev
|
33
|
+
end
|
34
|
+
|
14
35
|
def next_event
|
15
36
|
idx = @idx + 1
|
16
37
|
while idx < @stream.size
|
@@ -97,5 +97,58 @@ module Lydown::Rendering
|
|
97
97
|
def cmd_partBreak
|
98
98
|
@context.emit(:music, "\\break ") if (@context.render_mode == :part)
|
99
99
|
end
|
100
|
+
|
101
|
+
def cmd_scoreBreak
|
102
|
+
@context.emit(:music, "\\break ") if (@context.render_mode == :score)
|
103
|
+
end
|
104
|
+
|
105
|
+
def cmd_partPageBreak
|
106
|
+
@context.emit(:music, "\\pageBreak ") if (@context.render_mode == :part)
|
107
|
+
end
|
108
|
+
|
109
|
+
def cmd_scorePageBreak
|
110
|
+
@context.emit(:music, "\\pageBreak ") if (@context.render_mode == :score)
|
111
|
+
end
|
112
|
+
|
113
|
+
def transform_slur_arguments(args)
|
114
|
+
case args.size
|
115
|
+
when 4
|
116
|
+
args = args.map do |a|
|
117
|
+
case a
|
118
|
+
when '_'
|
119
|
+
'#f'
|
120
|
+
when /\(([0-9\.\-]*),([0-9\.\-]*)\)/
|
121
|
+
"(#{$1.empty? ? '0' : $1} . #{$2.empty? ? '0' : $2})"
|
122
|
+
else
|
123
|
+
a
|
124
|
+
end
|
125
|
+
end
|
126
|
+
args.join(" ")
|
127
|
+
when 1
|
128
|
+
args[0].gsub(/_/, ' (0 . 0) ').
|
129
|
+
gsub (/\(([0-9\.\-]*),([0-9\.\-]*)\)/) do |m|
|
130
|
+
"(#{$1.empty? ? '0' : $1} . #{$2.empty? ? '0' : $2})"
|
131
|
+
end
|
132
|
+
else
|
133
|
+
raise "Invalid slur shape arguments (#{args.inspect})"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def cmd_slur
|
138
|
+
arguments = transform_slur_arguments(@event[:arguments])
|
139
|
+
@context.emit(:music, "\\sS #'(#{arguments}) ")
|
140
|
+
end
|
141
|
+
|
142
|
+
# height-limit + eccentricity
|
143
|
+
def cmd_sHLE
|
144
|
+
args = @event[:arguments]
|
145
|
+
@context.emit(:music, "\\sHL #{args[0]} \\sE #{args[1]} ")
|
146
|
+
end
|
147
|
+
|
148
|
+
# positions
|
149
|
+
def cmd_sP
|
150
|
+
args = @event[:arguments]
|
151
|
+
@context.emit(:music, "\\sP #{args.join(' ')} ")
|
152
|
+
end
|
100
153
|
end
|
101
154
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
module Lydown::Rendering
|
7
|
+
module Layout
|
8
|
+
def self.define_paper_size(layout)
|
9
|
+
return "" unless layout[:paper]
|
10
|
+
|
11
|
+
if layout[:paper] =~ /([^\s]+)\s?(portrait|landscape)?/
|
12
|
+
size = $1
|
13
|
+
orientation = $2 || 'portrait'
|
14
|
+
else
|
15
|
+
size = layout[:paper]
|
16
|
+
orientation = 'portrait'
|
17
|
+
end
|
18
|
+
|
19
|
+
"#(set-paper-size \"#{size.downcase}\" '#{orientation})"
|
20
|
+
end
|
21
|
+
|
22
|
+
POINT_DIV = {
|
23
|
+
mm: 0.352778,
|
24
|
+
cm: 3.52778
|
25
|
+
}
|
26
|
+
|
27
|
+
MEASUREMENT_RE = /^([0-9\-\.]+)(mm|cm)$/
|
28
|
+
|
29
|
+
def self.to_pp(v)
|
30
|
+
if v =~ MEASUREMENT_RE
|
31
|
+
value = $1
|
32
|
+
unit = $2
|
33
|
+
|
34
|
+
factor = POINT_DIV[unit.to_sym]
|
35
|
+
"%.1f" % (value.to_f / factor)
|
36
|
+
else
|
37
|
+
raise "Invalid measurement #{v}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.fmt(v)
|
42
|
+
if v =~ MEASUREMENT_RE
|
43
|
+
"#{$1}\\#{$2}"
|
44
|
+
else
|
45
|
+
raise "Invalid measurement #{v}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.to_v(v)
|
50
|
+
if v =~ MEASUREMENT_RE
|
51
|
+
$1.to_f
|
52
|
+
else
|
53
|
+
raise "Invalid measurement #{v}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# in points
|
58
|
+
def self.staff_space(info)
|
59
|
+
to_v(info[:staff_size]) / 4
|
60
|
+
end
|
61
|
+
|
62
|
+
# calculates inner vertical margins - that is, the space between the defined
|
63
|
+
# actual margin (used for header/footer) and the music/markup.
|
64
|
+
# an array of four values is returned: top-content, bottom-content
|
65
|
+
def self.calculate_vertical_margins(info)
|
66
|
+
ss = staff_space(info)
|
67
|
+
|
68
|
+
dist = lambda do |k|
|
69
|
+
(to_v(info["#{k}_content"]) - to_v(info[k])) / ss
|
70
|
+
end
|
71
|
+
|
72
|
+
staff_dist = lambda {|k| dist[k] + 2}
|
73
|
+
|
74
|
+
[
|
75
|
+
"%.1f" % staff_dist[:margin_top],
|
76
|
+
"%.1f" % dist[:margin_top],
|
77
|
+
"%.1f" % staff_dist[:margin_bottom]
|
78
|
+
]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|