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.
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
+ }