lydown 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +159 -2
  3. data/lib/lydown.rb +8 -2
  4. data/lib/lydown/cache.rb +54 -0
  5. data/lib/lydown/cli.rb +1 -0
  6. data/lib/lydown/cli/commands.rb +27 -9
  7. data/lib/lydown/cli/compiler.rb +218 -54
  8. data/lib/lydown/cli/diff.rb +1 -1
  9. data/lib/lydown/cli/proofing.rb +3 -3
  10. data/lib/lydown/cli/signals.rb +23 -0
  11. data/lib/lydown/cli/support.rb +23 -1
  12. data/lib/lydown/core_ext.rb +41 -5
  13. data/lib/lydown/{rendering/defaults.yml → defaults.yml} +3 -3
  14. data/lib/lydown/errors.rb +3 -0
  15. data/lib/lydown/lilypond.rb +73 -31
  16. data/lib/lydown/ly_lib/lib.ly +297 -0
  17. data/lib/lydown/parsing.rb +1 -2
  18. data/lib/lydown/parsing/lydown.treetop +16 -10
  19. data/lib/lydown/parsing/nodes.rb +29 -5
  20. data/lib/lydown/rendering.rb +32 -6
  21. data/lib/lydown/rendering/command.rb +79 -2
  22. data/lib/lydown/rendering/figures.rb +29 -8
  23. data/lib/lydown/rendering/literal.rb +7 -0
  24. data/lib/lydown/rendering/movement.rb +61 -0
  25. data/lib/lydown/rendering/music.rb +37 -5
  26. data/lib/lydown/rendering/notes.rb +26 -8
  27. data/lib/lydown/rendering/settings.rb +41 -13
  28. data/lib/lydown/rendering/skipping.rb +43 -10
  29. data/lib/lydown/rendering/staff.rb +72 -16
  30. data/lib/lydown/templates.rb +8 -2
  31. data/lib/lydown/templates/lilypond_doc.erb +10 -1
  32. data/lib/lydown/templates/movement.erb +87 -34
  33. data/lib/lydown/templates/multi_voice.erb +1 -1
  34. data/lib/lydown/templates/part.erb +83 -55
  35. data/lib/lydown/templates/variables.erb +38 -0
  36. data/lib/lydown/version.rb +1 -1
  37. data/lib/lydown/work.rb +39 -26
  38. data/lib/lydown/work_context.rb +252 -14
  39. metadata +138 -8
  40. data/lib/lydown/rendering/lib.ly +0 -88
@@ -45,7 +45,7 @@ module Lydown::CLI::Diff
45
45
  first += 1 if first
46
46
  last += 1 if last
47
47
 
48
- first..last
48
+ [first, last]
49
49
  rescue => e
50
50
  $stderr.puts e.message
51
51
  $stderr.puts e.backtrace.join("\n")
@@ -77,7 +77,7 @@ module Lydown::CLI::Proofing
77
77
  opts[:mode] = :score
78
78
  else
79
79
  opts[:parts] = [part]
80
- opts[:mode] = part
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] != (nil..nil)
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].inspect})"
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}
@@ -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] == 'ly'
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
+
@@ -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
- ROMAN = %w[0 I II III IV V VI VII VIII IX X XI XII XIII XIV XV XVI XVII XVIII XIX
173
- XX XXI XXII XXIII XXIV XXV XXVI XXVII XXVIII XXIX XXX]
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
- ROMAN[self]
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
@@ -1,2 +1,5 @@
1
1
  class LydownError < RuntimeError
2
+ end
3
+
4
+ class CompilationAbortError < RuntimeError
2
5
  end
@@ -13,10 +13,31 @@ module Lydown
13
13
  end
14
14
 
15
15
  def compile(source, opts = {})
16
- opts[:output_filename] ||= 'lydown'
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
- target = opts[:output_filename].dup
19
- ext = ".#{opts[:format] || 'pdf'}"
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
- format = opts[:format]
54
- format = nil if format == 'midi'
72
+ cmd = format_cmd(opts)
55
73
 
56
- # Run lilypond, pipe source into its STDIN, and capture its STDERR
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
- err_info = ''
64
- success = false
65
- Open3.popen2e(cmd) do |input, output, wait_thr|
66
- input.puts source
67
- input.close_write
68
- err_info = read_lilypond_progress(output, opts)
69
- output.close
70
- success = wait_thr.value == 0
71
- end
72
- unless success
73
- err_info = err_info.lines[0, 3].join
74
- raise LydownError, "Lilypond compilation failed:\n#{err_info}"
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
- Lydown::CLI::show_progress('Compile', STATUS_TOTAL) do |bar|
95
- while !f.eof?
96
- line = f.gets
97
- info += line
98
- if line =~ /^([^\s]+)/
99
- idx = LILYPOND_STATUS_LINES.index($1)
100
- bar.progress = idx + 1 if idx
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
+ }