lydown 0.9.0 → 0.10.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 +4 -4
- data/README.md +159 -2
- data/lib/lydown.rb +8 -2
- data/lib/lydown/cache.rb +54 -0
- data/lib/lydown/cli.rb +1 -0
- data/lib/lydown/cli/commands.rb +27 -9
- data/lib/lydown/cli/compiler.rb +218 -54
- data/lib/lydown/cli/diff.rb +1 -1
- data/lib/lydown/cli/proofing.rb +3 -3
- data/lib/lydown/cli/signals.rb +23 -0
- data/lib/lydown/cli/support.rb +23 -1
- data/lib/lydown/core_ext.rb +41 -5
- data/lib/lydown/{rendering/defaults.yml → defaults.yml} +3 -3
- data/lib/lydown/errors.rb +3 -0
- data/lib/lydown/lilypond.rb +73 -31
- data/lib/lydown/ly_lib/lib.ly +297 -0
- data/lib/lydown/parsing.rb +1 -2
- data/lib/lydown/parsing/lydown.treetop +16 -10
- data/lib/lydown/parsing/nodes.rb +29 -5
- data/lib/lydown/rendering.rb +32 -6
- data/lib/lydown/rendering/command.rb +79 -2
- data/lib/lydown/rendering/figures.rb +29 -8
- data/lib/lydown/rendering/literal.rb +7 -0
- data/lib/lydown/rendering/movement.rb +61 -0
- data/lib/lydown/rendering/music.rb +37 -5
- data/lib/lydown/rendering/notes.rb +26 -8
- data/lib/lydown/rendering/settings.rb +41 -13
- data/lib/lydown/rendering/skipping.rb +43 -10
- data/lib/lydown/rendering/staff.rb +72 -16
- data/lib/lydown/templates.rb +8 -2
- data/lib/lydown/templates/lilypond_doc.erb +10 -1
- data/lib/lydown/templates/movement.erb +87 -34
- data/lib/lydown/templates/multi_voice.erb +1 -1
- data/lib/lydown/templates/part.erb +83 -55
- data/lib/lydown/templates/variables.erb +38 -0
- data/lib/lydown/version.rb +1 -1
- data/lib/lydown/work.rb +39 -26
- data/lib/lydown/work_context.rb +252 -14
- metadata +138 -8
- data/lib/lydown/rendering/lib.ly +0 -88
data/lib/lydown/cli/diff.rb
CHANGED
data/lib/lydown/cli/proofing.rb
CHANGED
@@ -77,7 +77,7 @@ module Lydown::CLI::Proofing
|
|
77
77
|
opts[:mode] = :score
|
78
78
|
else
|
79
79
|
opts[:parts] = [part]
|
80
|
-
opts[:mode] =
|
80
|
+
opts[:mode] = :proof
|
81
81
|
opts[:line_range] = Lydown::CLI::Diff.diff_line_range(path)
|
82
82
|
end
|
83
83
|
|
@@ -85,9 +85,9 @@ module Lydown::CLI::Proofing
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def process(opts)
|
88
|
-
if opts[:line_range] !=
|
88
|
+
if opts[:line_range] != [nil, nil]
|
89
89
|
t = Time.now.strftime("%H:%M:%S")
|
90
|
-
$stderr.puts "[#{t}] Changed: #{opts[:base_path]} (lines #{opts[:line_range]
|
90
|
+
$stderr.puts "[#{t}] Changed: #{opts[:base_path]} (lines #{opts[:line_range][0]}..#{opts[:line_range][1]})"
|
91
91
|
Lydown::CLI::Compiler.process(opts)
|
92
92
|
end
|
93
93
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Lydown::CLI
|
2
|
+
@@abortable_child_processes = []
|
3
|
+
|
4
|
+
def self.abort
|
5
|
+
$stderr.puts
|
6
|
+
if pid = @@abortable_child_processes.last
|
7
|
+
Process.kill("INT", pid)
|
8
|
+
else
|
9
|
+
exit
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.register_abortable_process(pid)
|
14
|
+
@@abortable_child_processes << pid
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.unregister_abortable_process(pid)
|
18
|
+
@@abortable_child_processes.delete pid
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Signal.trap("INT") {Lydown::CLI.abort}
|
23
|
+
Signal.trap("TERM") {exit}
|
data/lib/lydown/cli/support.rb
CHANGED
@@ -14,7 +14,7 @@ module Lydown::CLI::Support
|
|
14
14
|
|
15
15
|
# the output defaults to a file named lydown expect if the format is ly.
|
16
16
|
# In that case the output will be sent to STDOUT.
|
17
|
-
options[:output_filename] ||= 'lydown' unless options[:format] ==
|
17
|
+
options[:output_filename] ||= 'lydown' unless options[:format] == :ly
|
18
18
|
else
|
19
19
|
options[:source_filename] = options[:path]
|
20
20
|
if (options[:path] !~ /\.ld$/) and File.file?(options[:path] + ".ld")
|
@@ -31,4 +31,26 @@ module Lydown::CLI::Support
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
34
|
+
|
35
|
+
# determine if the specified path is actually a path to a single movement of
|
36
|
+
# a multi-movement work. If so, return the path of the work directory, and
|
37
|
+
# add a movement parameter. This should also take care of running proof
|
38
|
+
# mode inside of a movement directory.
|
39
|
+
def self.detect_work_directory(opts)
|
40
|
+
return if opts[:movements]
|
41
|
+
|
42
|
+
parent_dir = File.expand_path(File.join(opts[:path], '..'))
|
43
|
+
|
44
|
+
if !File.exists?(File.join(opts[:path], 'work.ld')) &&
|
45
|
+
File.exists?(File.expand_path(File.join(parent_dir, 'work.ld')))
|
46
|
+
|
47
|
+
movement = File.basename(File.expand_path(opts[:path]))
|
48
|
+
opts[:movements] = [movement] unless opts[:mode] == :proof
|
49
|
+
opts[:path] = parent_dir
|
50
|
+
end
|
51
|
+
end
|
34
52
|
end
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
|
data/lib/lydown/core_ext.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'escape_utils'
|
2
|
+
require 'pathname'
|
2
3
|
|
3
4
|
class Hash
|
4
5
|
# Merges self with another hash, recursively.
|
@@ -62,7 +63,7 @@ class Hash
|
|
62
63
|
if @deep && k.is_a?(String) && k =~ /\//
|
63
64
|
lookup(k)
|
64
65
|
elsif @deep && k.is_a?(Symbol)
|
65
|
-
old_get(k) || old_get(k.to_s)
|
66
|
+
old_get(k) || old_get(k.to_s)
|
66
67
|
else
|
67
68
|
old_get(k)
|
68
69
|
end
|
@@ -105,6 +106,12 @@ class Hash
|
|
105
106
|
def is_deep?
|
106
107
|
!!@deep
|
107
108
|
end
|
109
|
+
|
110
|
+
def stringify_keys
|
111
|
+
h = {}
|
112
|
+
each {|k, v| h[k.to_s] = v}
|
113
|
+
h
|
114
|
+
end
|
108
115
|
end
|
109
116
|
|
110
117
|
class String
|
@@ -169,11 +176,40 @@ class String
|
|
169
176
|
end
|
170
177
|
|
171
178
|
class Fixnum
|
172
|
-
|
173
|
-
|
174
|
-
|
179
|
+
# Taken from https://github.com/AndrewVos/roman-numerals
|
180
|
+
# Copyright (c) 2011 Andrew Vos
|
181
|
+
@@roman_digits = {
|
182
|
+
1000 => 'M',
|
183
|
+
900 => 'CM',
|
184
|
+
500 => 'D',
|
185
|
+
400 => 'CD',
|
186
|
+
100 => 'C',
|
187
|
+
90 => 'XC',
|
188
|
+
50 => 'L',
|
189
|
+
40 => 'XL',
|
190
|
+
10 => 'X',
|
191
|
+
9 => 'IX',
|
192
|
+
5 => 'V',
|
193
|
+
4 => 'IV',
|
194
|
+
1 => 'I'
|
195
|
+
}
|
196
|
+
|
175
197
|
def to_roman
|
176
|
-
|
198
|
+
result = ''
|
199
|
+
value = self
|
200
|
+
@@roman_digits.keys.each do |decimal|
|
201
|
+
while value >= decimal
|
202
|
+
value -= decimal
|
203
|
+
result += @@roman_digits[decimal]
|
204
|
+
end
|
205
|
+
end
|
206
|
+
result
|
177
207
|
end
|
178
208
|
end
|
179
209
|
|
210
|
+
class Pathname
|
211
|
+
# Returns path relative to working directory
|
212
|
+
def self.relative_pwd(path)
|
213
|
+
self.new(path).relative_path_from(pwd).to_s
|
214
|
+
end
|
215
|
+
end
|
@@ -148,6 +148,7 @@ parts:
|
|
148
148
|
clef: bass
|
149
149
|
midi_instrument: cello
|
150
150
|
embed_figures: true
|
151
|
+
remove_empty: false
|
151
152
|
organo:
|
152
153
|
clef: bass
|
153
154
|
midi_instrument: church organ
|
@@ -182,7 +183,6 @@ score:
|
|
182
183
|
- [violino, violino1, violino2, violino3, violin1, violin2, violin3]
|
183
184
|
- viola
|
184
185
|
- [gamba, gamba1, gamba2]
|
185
|
-
- [soprano, alto, tenore, basso]
|
186
|
-
- [soprano1, alto1, tenore1, basso1]
|
187
|
-
- [soprano2, alto2, tenore2, basso2]
|
186
|
+
- [soprano1, soprano2, soprano, alto1, alto2, alto, tenore1, tenore2, tenore, basso1, basso2, basso]
|
188
187
|
- continuo
|
188
|
+
end_barline: "|."
|
data/lib/lydown/errors.rb
CHANGED
data/lib/lydown/lilypond.rb
CHANGED
@@ -13,10 +13,31 @@ module Lydown
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def compile(source, opts = {})
|
16
|
-
opts[:
|
16
|
+
opts[:output_target] ||= 'lydown'
|
17
|
+
|
18
|
+
if opts[:temp]
|
19
|
+
opts[:output_filename] = opts[:output_target]
|
20
|
+
invoke(source, opts)
|
21
|
+
else
|
22
|
+
invoke_with_tempfile(source, opts)
|
23
|
+
end
|
17
24
|
|
18
|
-
|
19
|
-
|
25
|
+
rescue CompilationAbortError => e
|
26
|
+
raise e
|
27
|
+
rescue => e
|
28
|
+
$stderr.puts e.message
|
29
|
+
$stderr.puts e.backtrace.join("\n") unless e.is_a?(LydownError)
|
30
|
+
raise e
|
31
|
+
end
|
32
|
+
|
33
|
+
# Compile into a tempfile. We do this because lilypond's behavior when
|
34
|
+
# supplied with target filenames is broken. If it is given a target
|
35
|
+
# path which corresponds to an existing directory name, it does not use
|
36
|
+
# the specified path plus extension, but instead creates a file inside
|
37
|
+
# the directory.
|
38
|
+
def invoke_with_tempfile(source, opts)
|
39
|
+
target = opts[:output_target].dup
|
40
|
+
ext = ".#{opts[:format] || :pdf}"
|
20
41
|
if target !~ /#{ext}$/
|
21
42
|
target << ext
|
22
43
|
end
|
@@ -25,15 +46,12 @@ module Lydown
|
|
25
46
|
opts[:output_filename] = tmp_target
|
26
47
|
invoke(source, opts)
|
27
48
|
|
49
|
+
# Copy tempfile to target
|
28
50
|
if File.file?(tmp_target + ext)
|
29
51
|
FileUtils.cp(tmp_target + ext, target)
|
30
52
|
else
|
31
53
|
copy_pages(tmp_target, target, ext)
|
32
54
|
end
|
33
|
-
rescue => e
|
34
|
-
$stderr.puts e.message
|
35
|
-
$stderr.puts e.backtrace.join("\n")
|
36
|
-
raise e
|
37
55
|
end
|
38
56
|
|
39
57
|
def copy_pages(source, target, ext)
|
@@ -49,30 +67,49 @@ module Lydown
|
|
49
67
|
end
|
50
68
|
end
|
51
69
|
|
70
|
+
# Run lilypond, pipe source into its STDIN, and capture its STDERR
|
52
71
|
def invoke(source, opts = {})
|
53
|
-
|
54
|
-
format = nil if format == 'midi'
|
72
|
+
cmd = format_cmd(opts)
|
55
73
|
|
56
|
-
|
74
|
+
err_info = ''
|
75
|
+
exit_value = nil
|
76
|
+
Open3.popen2e(cmd) do |input, output, wait_thr|
|
77
|
+
err_info = exec(wait_thr, input, output, source, opts)
|
78
|
+
exit_value = wait_thr.value
|
79
|
+
end
|
80
|
+
if exit_value != 0
|
81
|
+
if exit_value.termsig
|
82
|
+
raise CompilationAbortError
|
83
|
+
else
|
84
|
+
# err_info = err_info.lines[0, 3].join
|
85
|
+
raise LydownError, "Lilypond compilation failed:\n#{err_info}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def format_cmd(opts)
|
91
|
+
format = opts[:format]
|
92
|
+
format = nil if (format == :midi) || (format == :mp3)
|
93
|
+
|
57
94
|
cmd = 'lilypond '
|
95
|
+
cmd << "-dbackend=eps " if opts[:mode] == :proof
|
58
96
|
cmd << "-o #{opts[:output_filename]} "
|
59
97
|
cmd << "-dno-point-and-click "
|
60
98
|
cmd << "--#{opts[:format]} " if format
|
61
99
|
cmd << ' - '
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
100
|
+
|
101
|
+
cmd
|
102
|
+
end
|
103
|
+
|
104
|
+
def exec(wait_thr, input, output, source, opts)
|
105
|
+
Lydown::CLI.register_abortable_process(wait_thr.pid)
|
106
|
+
input.puts source
|
107
|
+
input.close_write
|
108
|
+
err_info = read_lilypond_progress(output, opts)
|
109
|
+
output.close
|
110
|
+
err_info
|
111
|
+
ensure
|
112
|
+
Lydown::CLI.unregister_abortable_process(wait_thr.pid)
|
76
113
|
end
|
77
114
|
|
78
115
|
LILYPOND_STATUS_LINES = %w{
|
@@ -91,18 +128,23 @@ module Lydown
|
|
91
128
|
|
92
129
|
def read_lilypond_progress(f, opts)
|
93
130
|
info = ''
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
131
|
+
unless opts[:no_progress_bar]
|
132
|
+
Lydown::CLI::show_progress('Compile', STATUS_TOTAL) do |bar|
|
133
|
+
while !f.eof?
|
134
|
+
line = f.gets
|
135
|
+
info += line
|
136
|
+
if line =~ /^([^\s]+)/
|
137
|
+
idx = LILYPOND_STATUS_LINES.index($1)
|
138
|
+
bar.progress = idx + 1 if idx
|
139
|
+
end
|
101
140
|
end
|
102
141
|
end
|
142
|
+
else
|
143
|
+
info = f.read
|
103
144
|
end
|
104
145
|
info
|
105
146
|
end
|
147
|
+
|
106
148
|
end
|
107
149
|
end
|
108
150
|
end
|
@@ -0,0 +1,297 @@
|
|
1
|
+
\header {
|
2
|
+
tagline = ##f
|
3
|
+
}
|
4
|
+
|
5
|
+
segno = {
|
6
|
+
\once \override Score.RehearsalMark #'font-size = #-2
|
7
|
+
\mark \markup { \musicglyph #"scripts.segno" }
|
8
|
+
}
|
9
|
+
|
10
|
+
segnobottom = {
|
11
|
+
\once \override Score.RehearsalMark #'direction = #DOWN
|
12
|
+
\once \override Score.RehearsalMark #'font-size = #-2
|
13
|
+
\mark \markup { \musicglyph #"scripts.segno" }
|
14
|
+
}
|
15
|
+
|
16
|
+
dalsegno = {
|
17
|
+
\once \override Score.RehearsalMark #'break-visibility = #begin-of-line-invisible
|
18
|
+
\once \override Score.RehearsalMark #'direction = #DOWN
|
19
|
+
\once \override Score.RehearsalMark #'self-alignment-X = #RIGHT
|
20
|
+
\once \override Score.RehearsalMark #'font-size = #-2
|
21
|
+
\mark \markup { \fontsize #2 {"dal segno "} \musicglyph #"scripts.segno" }
|
22
|
+
}
|
23
|
+
|
24
|
+
dacapo = {
|
25
|
+
\once \override Score.RehearsalMark #'break-visibility = #begin-of-line-invisible
|
26
|
+
\once \override Score.RehearsalMark #'direction = #DOWN
|
27
|
+
\once \override Score.RehearsalMark #'self-alignment-X = #RIGHT
|
28
|
+
\mark \markup {\bold {\italic {"Da capo"}}}
|
29
|
+
}
|
30
|
+
|
31
|
+
dalsegnoadlib = {
|
32
|
+
\once \override Score.RehearsalMark #'direction = #DOWN
|
33
|
+
\once \override Score.RehearsalMark #'self-alignment-X = #LEFT
|
34
|
+
\once \override Score.RehearsalMark #'font-size = #-2
|
35
|
+
\mark \markup { \musicglyph #"scripts.segno" ad lib }
|
36
|
+
}
|
37
|
+
|
38
|
+
finedellaparteprima = {
|
39
|
+
\once \override Score.RehearsalMark #'break-visibility = #begin-of-line-invisible
|
40
|
+
\once \override Score.RehearsalMark #'direction = #DOWN
|
41
|
+
\once \override Score.RehearsalMark #'self-alignment-X = #RIGHT
|
42
|
+
\mark \markup {\bold {\italic {"Fine della parte prima"}}}
|
43
|
+
}
|
44
|
+
|
45
|
+
padbarlinebefore = {
|
46
|
+
\once \override Staff.BarLine #'extra-spacing-width = #'(-2 . 0)
|
47
|
+
}
|
48
|
+
|
49
|
+
padbarlineafter = {
|
50
|
+
\once \override Staff.BarLine #'extra-spacing-width = #'(0 . 2)
|
51
|
+
}
|
52
|
+
|
53
|
+
editF = \markup { \center-align \concat { \bold { \italic ( }
|
54
|
+
\dynamic f \bold { \italic ) } } }
|
55
|
+
editP = \markup { \center-align \concat { \bold { \italic ( }
|
56
|
+
\dynamic p \bold { \italic ) } } }
|
57
|
+
editPP = \markup { \center-align \concat { \bold { \italic ( }
|
58
|
+
\dynamic pp \bold { \italic ) } } }
|
59
|
+
|
60
|
+
doux = \markup { \center-align \bold { \italic doux }}
|
61
|
+
fort = \markup { \center-align \bold { \italic fort }}
|
62
|
+
|
63
|
+
ten = \markup { \italic ten. }
|
64
|
+
|
65
|
+
ficta = {
|
66
|
+
\once \override AccidentalSuggestion #'avoid-slur = #'outside
|
67
|
+
\once \set suggestAccidentals = ##t
|
68
|
+
}
|
69
|
+
|
70
|
+
%{
|
71
|
+
http://www.lilypond.org/doc/v2.18/Documentation/snippets/editorial-annotations#editorial-annotations-adding-links-to-objects
|
72
|
+
%}
|
73
|
+
#(define (add-link url-strg)
|
74
|
+
(lambda (grob)
|
75
|
+
(let* ((stil (ly:grob-property grob 'stencil)))
|
76
|
+
(if (ly:stencil? stil)
|
77
|
+
(begin
|
78
|
+
(let* (
|
79
|
+
(x-ext (ly:stencil-extent stil X))
|
80
|
+
(y-ext (ly:stencil-extent stil Y))
|
81
|
+
(url-expr (list 'url-link url-strg `(quote ,x-ext) `(quote ,y-ext)))
|
82
|
+
(new-stil (ly:stencil-add (ly:make-stencil url-expr x-ext y-ext) stil)))
|
83
|
+
(ly:grob-set-property! grob 'stencil new-stil)))
|
84
|
+
#f))))
|
85
|
+
|
86
|
+
|
87
|
+
\layout {
|
88
|
+
#(layout-set-staff-size 14)
|
89
|
+
indent = 0\cm
|
90
|
+
|
91
|
+
\context {
|
92
|
+
\Score
|
93
|
+
\override InstrumentName #'self-alignment-X = #right
|
94
|
+
\override InstrumentName #'padding = 0.6
|
95
|
+
|
96
|
+
\override BarNumber #'padding = 1.5
|
97
|
+
|
98
|
+
%make note stems a bit thicker
|
99
|
+
\override Stem.thickness = #2
|
100
|
+
|
101
|
+
% slurs and ties are a bit curvier and thicker
|
102
|
+
% ties are also a bit more distant from note heads
|
103
|
+
% all that with a bit of randomness
|
104
|
+
\override Slur.eccentricity = #(lambda (grob) (* 0.05 (random:normal)))
|
105
|
+
\override Slur.height-limit = #(lambda (grob) (+ 2.8 (* 0.2 (random:normal))))
|
106
|
+
\override Slur.thickness = #(lambda (grob) (+ 2.9 (* 0.1 (random:normal))))
|
107
|
+
\override Slur.ratio = #(lambda (grob) (+ 0.3 (* 0.05 (random:normal))))
|
108
|
+
|
109
|
+
\override Tie.thickness = #(lambda (grob) (+ 2.9 (* 0.1 (random:normal))))
|
110
|
+
\override Tie.ratio = #(lambda (grob) (+ 0.3 (* 0.05 (random:normal))))
|
111
|
+
\override Tie #'details #'note-head-gap = #(lambda (grob) (+ 0.5 (* 0.1 (random:normal))))
|
112
|
+
|
113
|
+
\override Beam.beam-thickness = #(lambda (grob) (+ 0.55 (* 0.02 (random:normal))))
|
114
|
+
\override Beam.length-fraction = #1.15
|
115
|
+
|
116
|
+
% \remove "Bar_number_engraver"
|
117
|
+
}
|
118
|
+
|
119
|
+
\context {
|
120
|
+
\Staff
|
121
|
+
\override StaffSymbol.color = #(rgb-color 0.25 0.2 0.2)
|
122
|
+
|
123
|
+
}
|
124
|
+
|
125
|
+
\context {
|
126
|
+
\Lyrics
|
127
|
+
% candidates: Georgia, Hoefler Text, Hoefler Text Italic,
|
128
|
+
%
|
129
|
+
\override LyricText #'font-name = #"Hoefler Text"
|
130
|
+
% \override LyricText #'font-size = #3
|
131
|
+
}
|
132
|
+
|
133
|
+
\context {
|
134
|
+
\override MarkupText #'font-name = #"Hoefler Text"
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
138
|
+
\paper {
|
139
|
+
% #(set-default-paper-size "A5")
|
140
|
+
|
141
|
+
% system-system-spacing #'basic-distance = #17
|
142
|
+
|
143
|
+
top-margin = 1.4\cm
|
144
|
+
bottom-margin = 1.4\cm
|
145
|
+
two-sided = ##t
|
146
|
+
inner-margin = 1.4\cm
|
147
|
+
outer-margin = 2\cm
|
148
|
+
|
149
|
+
markup-system-spacing #'padding = #3
|
150
|
+
markup-system-spacing #'stretchability = #10
|
151
|
+
score-markup-spacing #'padding = #7
|
152
|
+
top-system-spacing #'padding = #3
|
153
|
+
top-markup-spacing #'padding = #3
|
154
|
+
system-system-spacing #'minimum-distance = #9
|
155
|
+
system-system-spacing #'stretchability = #15
|
156
|
+
|
157
|
+
|
158
|
+
% ragged-last-bottom = ##t
|
159
|
+
ragged-bottom = ##t
|
160
|
+
|
161
|
+
print-first-page-number = ##f
|
162
|
+
|
163
|
+
oddHeaderMarkup = \markup
|
164
|
+
\fill-line {
|
165
|
+
%% force the header to take some space, otherwise the
|
166
|
+
%% page layout becomes a complete mess.
|
167
|
+
" "
|
168
|
+
% \on-the-fly #not-first-page {
|
169
|
+
\on-the-fly #print-page-number-check-first \fromproperty #'page:page-number-string
|
170
|
+
% }
|
171
|
+
}
|
172
|
+
|
173
|
+
evenHeaderMarkup = \markup
|
174
|
+
\fill-line {
|
175
|
+
\on-the-fly #print-page-number-check-first \fromproperty #'page:page-number-string
|
176
|
+
" "
|
177
|
+
}
|
178
|
+
|
179
|
+
}
|
180
|
+
|
181
|
+
% trill = #(make-articulation "stopped")
|
182
|
+
trillSharp = #(make-articulation "trillSharp")
|
183
|
+
trillNatural = #(make-articulation "trillNatural")
|
184
|
+
tr = #(make-articulation "t")
|
185
|
+
trillSug = #(make-articulation "trillSug")
|
186
|
+
prallSug = #(make-articulation "prallSug")
|
187
|
+
arcTrill = #(make-articulation "arcTrill")
|
188
|
+
arcDot = #(make-articulation "arcDot")
|
189
|
+
arcArc = #(make-articulation "arcArc")
|
190
|
+
arcArcDot = #(make-articulation "arcArcDot")
|
191
|
+
dotDot = #(make-articulation "dotDot")
|
192
|
+
dotPrall = #(make-articulation "dotPrall")
|
193
|
+
dotDoublePrallDoublePrall = #(make-articulation "dotDoublePrallDoublePrall")
|
194
|
+
doublePrall = #(make-articulation "doublePrall")
|
195
|
+
|
196
|
+
prallupbefore = {
|
197
|
+
\mark\markup {
|
198
|
+
\musicglyph #"scripts.prallup"
|
199
|
+
\hspace #1
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
% override the figured bass formatter in order to fix size of figure accidentals
|
204
|
+
#(define-public (better-format-bass-figure figure event context)
|
205
|
+
(let* ((fig (ly:event-property event 'figure))
|
206
|
+
(fig-markup (if (number? figure)
|
207
|
+
|
208
|
+
;; this is not very elegant, but center-aligning
|
209
|
+
;; all digits is problematic with other markups,
|
210
|
+
;; and shows problems in the (lack of) overshoot
|
211
|
+
;; of feta-alphabet glyphs.
|
212
|
+
((if (<= 10 figure)
|
213
|
+
(lambda (y) (make-translate-scaled-markup
|
214
|
+
(cons -0.7 0) y))
|
215
|
+
identity)
|
216
|
+
|
217
|
+
(cond
|
218
|
+
((eq? #t (ly:event-property event 'diminished))
|
219
|
+
(markup #:slashed-digit figure))
|
220
|
+
((eq? #t (ly:event-property event 'augmented-slash))
|
221
|
+
(markup #:backslashed-digit figure))
|
222
|
+
(else (markup #:number (number->string figure 10)))))
|
223
|
+
#f))
|
224
|
+
|
225
|
+
(alt (ly:event-property event 'alteration))
|
226
|
+
(alt-markup
|
227
|
+
(if (number? alt)
|
228
|
+
(markup
|
229
|
+
#:general-align Y DOWN #:fontsize
|
230
|
+
(if (not (= alt DOUBLE-SHARP))
|
231
|
+
0 2)
|
232
|
+
(alteration->text-accidental-markup alt))
|
233
|
+
#f))
|
234
|
+
|
235
|
+
(plus-markup (if (eq? #t (ly:event-property event 'augmented))
|
236
|
+
(markup #:number "+")
|
237
|
+
#f))
|
238
|
+
|
239
|
+
(alt-dir (ly:context-property context 'figuredBassAlterationDirection))
|
240
|
+
(plus-dir (ly:context-property context 'figuredBassPlusDirection)))
|
241
|
+
|
242
|
+
(if (and (not fig-markup) alt-markup)
|
243
|
+
(begin
|
244
|
+
(set! fig-markup (markup #:left-align #:pad-around 0.2 alt-markup))
|
245
|
+
(set! alt-markup #f)))
|
246
|
+
|
247
|
+
|
248
|
+
;; hmm, how to get figures centered between note, and
|
249
|
+
;; lone accidentals too?
|
250
|
+
|
251
|
+
;; (if (markup? fig-markup)
|
252
|
+
;; (set!
|
253
|
+
;; fig-markup (markup #:translate (cons 1.0 0)
|
254
|
+
;; #:center-align fig-markup)))
|
255
|
+
|
256
|
+
(if alt-markup
|
257
|
+
(set! fig-markup
|
258
|
+
(markup #:put-adjacent
|
259
|
+
X (if (number? alt-dir)
|
260
|
+
alt-dir
|
261
|
+
LEFT)
|
262
|
+
fig-markup
|
263
|
+
#:pad-x 0.2 #:lower 0.1 alt-markup)))
|
264
|
+
|
265
|
+
(if plus-markup
|
266
|
+
(set! fig-markup
|
267
|
+
(if fig-markup
|
268
|
+
(markup #:put-adjacent
|
269
|
+
X (if (number? plus-dir)
|
270
|
+
plus-dir
|
271
|
+
LEFT)
|
272
|
+
fig-markup
|
273
|
+
#:pad-x 0.2 plus-markup)
|
274
|
+
plus-markup)))
|
275
|
+
|
276
|
+
(if (markup? fig-markup)
|
277
|
+
(markup #:fontsize 0 fig-markup)
|
278
|
+
empty-markup)))
|
279
|
+
|
280
|
+
\layout {
|
281
|
+
\context {
|
282
|
+
\FiguredBass
|
283
|
+
figuredBassFormatter = #better-format-bass-figure
|
284
|
+
% \override BassFigure #'font-size = #-1
|
285
|
+
% \override BassFigure #'font-name = #"Georgia"
|
286
|
+
}
|
287
|
+
|
288
|
+
% \context {
|
289
|
+
% \StaffGroup
|
290
|
+
% \override StaffGrouper.staff-staff-spacing =
|
291
|
+
% #'((basic-distance . 10)
|
292
|
+
% (minimum-distance . 7)
|
293
|
+
% (padding . 0)
|
294
|
+
% (stretchability . 7))
|
295
|
+
%
|
296
|
+
% }
|
297
|
+
}
|