lydown 0.7.0 → 0.7.1
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/bin/lydown +42 -32
- data/lib/lydown/cli/compiler.rb +5 -0
- data/lib/lydown/cli/diff.rb +52 -0
- data/lib/lydown/cli/proofing.rb +97 -0
- data/lib/lydown/cli.rb +2 -0
- data/lib/lydown/lilypond.rb +19 -1
- data/lib/lydown/rendering/lib.ly +18 -1
- data/lib/lydown/templates/part.erb +4 -4
- data/lib/lydown/version.rb +1 -1
- data/lib/lydown/work.rb +41 -3
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f9e00d9938576429da9646dc782f2451c66afa9
|
4
|
+
data.tar.gz: 3fe22010c7e1928c74a5278eb659dc78922a53a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f18283718262a5404cb6e78ba0c155c3c0f750eaf3ddf47b3f5e6b460836980fb9019e2146bb093aa662e1da25625880fb935479e9766a47f565dd4107300516
|
7
|
+
data.tar.gz: 86b12d5d519691dc54f18fcfd061eb2d26a1d403780b3e8b5d800e32278bb78250841c818f1a76d7353fd5deffc99642d2eecf960c756205b06c7389a2e72650
|
data/bin/lydown
CHANGED
@@ -13,7 +13,7 @@ help = <<HELP
|
|
13
13
|
Lydown is not lilypond
|
14
14
|
HELP
|
15
15
|
|
16
|
-
$options = {'format' => 'pdf'}
|
16
|
+
$options = {'format' => 'pdf'}.deep!
|
17
17
|
opts = OptionParser.new do |opts|
|
18
18
|
opts.banner = help
|
19
19
|
|
@@ -23,64 +23,64 @@ opts = OptionParser.new do |opts|
|
|
23
23
|
end
|
24
24
|
|
25
25
|
opts.on("-p", "--parts PART", "Parts (comma-separated)") do |v|
|
26
|
-
$options[
|
26
|
+
$options[:parts] = v.split(',')
|
27
27
|
end
|
28
28
|
|
29
29
|
opts.on("-m", "--mvts MVT", "Movements (comma-separated)") do |v|
|
30
|
-
$options[
|
30
|
+
$options[:movements] = v.split(',')
|
31
31
|
end
|
32
32
|
|
33
33
|
opts.on("--no-score", "Do not generate secore") do
|
34
|
-
$options[
|
34
|
+
$options[:no_score] = true
|
35
35
|
end
|
36
36
|
|
37
37
|
opts.on("-s", "--score", "Generate only score, no parts") do
|
38
|
-
$options[
|
38
|
+
$options[:score_only] = true
|
39
39
|
end
|
40
40
|
|
41
41
|
opts.on("-V", "--vocal", "Generate only vocal score") do
|
42
|
-
$options[
|
42
|
+
$options[:vocal_only] = true
|
43
43
|
end
|
44
44
|
|
45
45
|
opts.on("--ly", "Generate Lilypond file") do
|
46
|
-
$options[
|
46
|
+
$options[:format] = 'ly'
|
47
47
|
end
|
48
48
|
|
49
49
|
opts.on("--pdf", "Generate PDF file") do
|
50
|
-
$options[
|
50
|
+
$options[:format] = 'pdf'
|
51
51
|
end
|
52
52
|
|
53
53
|
opts.on("--png", "Generate PNG file") do
|
54
|
-
$options[
|
54
|
+
$options[:format] = 'png'
|
55
55
|
end
|
56
56
|
|
57
57
|
opts.on("-M", "--midi", "Generate midi file") do
|
58
|
-
$options[
|
59
|
-
$options[
|
58
|
+
$options[:format] = 'midi'
|
59
|
+
$options[:score_only] = true # implied
|
60
60
|
end
|
61
61
|
|
62
62
|
opts.on("-P", "--proof", "Start proofing mode") do
|
63
|
-
$options[
|
63
|
+
$options[:open_target] = true
|
64
|
+
$options[:proof_mode] = true
|
64
65
|
end
|
65
66
|
|
66
67
|
opts.on("-O", "--open", "Open PDF/Midi file after processing") do
|
67
|
-
$options[
|
68
|
+
$options[:open_target] = true
|
68
69
|
end
|
69
70
|
|
70
71
|
opts.on("-o", "--output FILE", "Filename for output") do |v|
|
71
|
-
$options[
|
72
|
+
$options[:output_filename] = v
|
72
73
|
end
|
73
74
|
|
74
75
|
opts.on("-W", "--work", "Create new work") do
|
75
|
-
$options[
|
76
|
+
$options[:gen] = :work
|
76
77
|
end
|
77
78
|
end
|
78
79
|
|
79
80
|
opts.parse!
|
80
|
-
$options.deep!
|
81
81
|
|
82
|
-
if $options[
|
83
|
-
# Ripple.generate($options[
|
82
|
+
if $options[:gen]
|
83
|
+
# Ripple.generate($options[:gen], ARGV)
|
84
84
|
exit
|
85
85
|
end
|
86
86
|
|
@@ -91,26 +91,36 @@ if ARGV[0] == '-'
|
|
91
91
|
|
92
92
|
# the output defaults to a file named lydown expect if the format is ly.
|
93
93
|
# In that case the output will be sent to STDOUT.
|
94
|
-
$options[
|
94
|
+
$options[:output_filename] ||= 'lydown' unless $options[:format] == 'ly'
|
95
95
|
else
|
96
96
|
filename = ARGV[0] || '.'
|
97
|
-
$options[
|
97
|
+
$options[:source_filename] = filename
|
98
98
|
if (filename !~ /\.ld$/) and File.file?(filename + ".ld")
|
99
99
|
filename += ".ld"
|
100
100
|
end
|
101
101
|
|
102
|
-
$options[
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
102
|
+
unless $options[:output_filename]
|
103
|
+
if filename == '.'
|
104
|
+
$options[:output_filename] = File.basename(FileUtils.pwd)
|
105
|
+
else
|
106
|
+
$options[:output_filename] = (filename =~ /^(.+)\.ld$/) ? $1 : filename
|
107
|
+
end
|
108
|
+
end
|
108
109
|
end
|
109
110
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
111
|
+
if $options[:proof_mode]
|
112
|
+
Lydown::CLI::Proofing.start_proofing($options)
|
113
|
+
else
|
114
|
+
# compile score
|
115
|
+
unless $options[:no_score] || $options[:parts]
|
116
|
+
Lydown::CLI::Compiler.process($options.merge(mode: :score, parts: nil))
|
115
117
|
end
|
116
|
-
|
118
|
+
|
119
|
+
# compile parts
|
120
|
+
unless $options[:score_only] || !$options[:parts]
|
121
|
+
parts = $options[:parts]
|
122
|
+
parts.each do |p|
|
123
|
+
Lydown::CLI::Compiler.process($options.merge(mode: :part, parts: p))
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/lydown/cli/compiler.rb
CHANGED
@@ -68,6 +68,11 @@ module Lydown::CLI::Compiler
|
|
68
68
|
|
69
69
|
if opts[:open_target]
|
70
70
|
filename = "#{opts[:output_target]}.#{opts[:format]}"
|
71
|
+
|
72
|
+
unless File.file?(filename)
|
73
|
+
filename = "#{opts[:output_target]}-page1.#{opts[:format]}"
|
74
|
+
end
|
75
|
+
|
71
76
|
system("open #{filename}")
|
72
77
|
end
|
73
78
|
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'diff/lcs'
|
2
|
+
|
3
|
+
module Lydown::CLI::Diff
|
4
|
+
class << self
|
5
|
+
CACHE = {}
|
6
|
+
|
7
|
+
def cached_content(path)
|
8
|
+
CACHE[File.absolute_path(path)] || []
|
9
|
+
end
|
10
|
+
|
11
|
+
def set_cached_content(path, content)
|
12
|
+
CACHE[File.absolute_path(path)] = content
|
13
|
+
end
|
14
|
+
|
15
|
+
def fill_cache(dir)
|
16
|
+
count = 0
|
17
|
+
Dir["#{dir}/**/*.ld"].each do |path|
|
18
|
+
set_cached_content(path, read_content(path)) rescue nil
|
19
|
+
count += 1
|
20
|
+
end
|
21
|
+
puts "Cached #{count} files."
|
22
|
+
end
|
23
|
+
|
24
|
+
def read_content(path)
|
25
|
+
IO.read(path).lines.map {|l| l.chomp}
|
26
|
+
end
|
27
|
+
|
28
|
+
def diff_line_range(path)
|
29
|
+
new_version = read_content(path)
|
30
|
+
old_version = cached_content(path)
|
31
|
+
|
32
|
+
first = nil
|
33
|
+
last = nil
|
34
|
+
|
35
|
+
diffs = Diff::LCS.diff(old_version, new_version).each do |d|
|
36
|
+
d.each do |r|
|
37
|
+
line = r.to_a[1]
|
38
|
+
first = line if first.nil? || line < first
|
39
|
+
last = line if last.nil? || line > last
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
set_cached_content(path, new_version)
|
44
|
+
|
45
|
+
first..last
|
46
|
+
rescue => e
|
47
|
+
STDERR << e.message
|
48
|
+
STDERR << e.backtrace.join("\n")
|
49
|
+
nil..nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'directory_watcher'
|
2
|
+
|
3
|
+
module Lydown::CLI::Proofing
|
4
|
+
class << self
|
5
|
+
def start_proofing(opts)
|
6
|
+
source = opts[:source_filename]
|
7
|
+
|
8
|
+
Lydown::CLI::Diff.fill_cache(source)
|
9
|
+
|
10
|
+
puts "Proof mode: #{source} -> #{opts[:output_filename]}"
|
11
|
+
last_proof_path = nil
|
12
|
+
|
13
|
+
watch_directory(source, opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
def watch_directory(source, opts)
|
17
|
+
dw = DirectoryWatcher.new(File.expand_path(source))
|
18
|
+
dw.interval = 0.25
|
19
|
+
dw.glob = ["#{source}/**/*.ld"]
|
20
|
+
|
21
|
+
dw.reset(true)
|
22
|
+
dw.add_observer do |*args|
|
23
|
+
t = Time.now.strftime("%Y-%m-%d %H:%M:%S")
|
24
|
+
args.each do |e|
|
25
|
+
if e.type = :modified
|
26
|
+
path = File.expand_path(e.path)
|
27
|
+
if path =~ /^#{File.expand_path(source)}\/(.+)/
|
28
|
+
path = $1
|
29
|
+
end
|
30
|
+
puts "[#{t}] Changed: #{path}"
|
31
|
+
last_proof_path = e.path unless File.basename(e.path) == 'movement.ld'
|
32
|
+
process(opts.deep_merge opts_for_path(last_proof_path, opts)) if last_proof_path
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
trap("INT") {return}
|
38
|
+
dw.start
|
39
|
+
loop {sleep 1000}
|
40
|
+
ensure
|
41
|
+
dw.stop
|
42
|
+
end
|
43
|
+
|
44
|
+
def globs(path)
|
45
|
+
Dir.chdir(path) do
|
46
|
+
dirs = Dir['*'].select { |x| File.directory?(x) }
|
47
|
+
# exclude _ly, _pdf, _midi dirs
|
48
|
+
# ['ly_dir', 'pdf_dir', 'midi_dir'].map {|d| $config[d]}.each do |d|
|
49
|
+
# if d =~ /^\.\/(.*)/
|
50
|
+
# dirs -= [$1]
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
end
|
54
|
+
|
55
|
+
dirs = dirs.map { |x| "#{x}/**/*" }
|
56
|
+
dirs
|
57
|
+
end
|
58
|
+
|
59
|
+
def opts_for_path(path, opts)
|
60
|
+
path = path.gsub('/./', '/')
|
61
|
+
part = File.basename(path, '.*')
|
62
|
+
base = opts[:source_filename] || '.'
|
63
|
+
if base == '.'
|
64
|
+
base = File.expand_path(base)
|
65
|
+
end
|
66
|
+
dir = File.dirname(path)
|
67
|
+
if dir =~ /^\.\/(.+)$/
|
68
|
+
dir = $1
|
69
|
+
end
|
70
|
+
if dir =~ /#{base}\/([^\/]+)/
|
71
|
+
mvt = $1
|
72
|
+
else
|
73
|
+
mvt = nil
|
74
|
+
end
|
75
|
+
|
76
|
+
opts = {}.deep!
|
77
|
+
opts[:movements] = [mvt]
|
78
|
+
if opts[:score_only]
|
79
|
+
opts[:mode] = :score
|
80
|
+
else
|
81
|
+
opts[:parts] = [part]
|
82
|
+
opts[:mode] = part
|
83
|
+
opts[:line_range] = Lydown::CLI::Diff.diff_line_range(path)
|
84
|
+
end
|
85
|
+
|
86
|
+
opts
|
87
|
+
end
|
88
|
+
|
89
|
+
def process(opts)
|
90
|
+
if opts[:line_range] == (nil..nil)
|
91
|
+
puts "No change detected"
|
92
|
+
else
|
93
|
+
Lydown::CLI::Compiler.process(opts)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/lydown/cli.rb
CHANGED
data/lib/lydown/lilypond.rb
CHANGED
@@ -21,12 +21,30 @@ module Lydown
|
|
21
21
|
tmp_target = Tempfile.new('lydown').path
|
22
22
|
opts[:output_filename] = tmp_target
|
23
23
|
invoke(source, opts)
|
24
|
-
|
24
|
+
|
25
|
+
if File.file?(tmp_target + ext)
|
26
|
+
FileUtils.cp(tmp_target + ext, target)
|
27
|
+
else
|
28
|
+
copy_pages(tmp_target, target, ext)
|
29
|
+
end
|
25
30
|
rescue => e
|
26
31
|
puts e.message
|
27
32
|
p e.backtrace
|
28
33
|
end
|
29
34
|
|
35
|
+
def copy_pages(source, target, ext)
|
36
|
+
page = 1
|
37
|
+
loop do
|
38
|
+
source_fn = source + "-page#{page}" + ext
|
39
|
+
break unless File.file?(source_fn)
|
40
|
+
|
41
|
+
target_fn = target.dup.insert(target.index(/\.[^\.]+$/), "-page#{page}")
|
42
|
+
|
43
|
+
FileUtils.cp(source_fn, target_fn)
|
44
|
+
page += 1
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
30
48
|
def invoke(source, opts = {})
|
31
49
|
# Run lilypond, pipe source into its STDIN, and capture its STDERR
|
32
50
|
cmd = 'lilypond -lERROR '
|
data/lib/lydown/rendering/lib.ly
CHANGED
@@ -46,4 +46,21 @@ ten = \markup { \italic ten. }
|
|
46
46
|
ficta = {
|
47
47
|
\once \override AccidentalSuggestion #'avoid-slur = #'outside
|
48
48
|
\once \set suggestAccidentals = ##t
|
49
|
-
}
|
49
|
+
}
|
50
|
+
|
51
|
+
%{
|
52
|
+
http://www.lilypond.org/doc/v2.18/Documentation/snippets/editorial-annotations#editorial-annotations-adding-links-to-objects
|
53
|
+
%}
|
54
|
+
#(define (add-link url-strg)
|
55
|
+
(lambda (grob)
|
56
|
+
(let* ((stil (ly:grob-property grob 'stencil)))
|
57
|
+
(if (ly:stencil? stil)
|
58
|
+
(begin
|
59
|
+
(let* (
|
60
|
+
(x-ext (ly:stencil-extent stil X))
|
61
|
+
(y-ext (ly:stencil-extent stil Y))
|
62
|
+
(url-expr (list 'url-link url-strg `(quote ,x-ext) `(quote ,y-ext)))
|
63
|
+
(new-stil (ly:stencil-add (ly:make-stencil url-expr x-ext y-ext) stil)))
|
64
|
+
(ly:grob-set-property! grob 'stencil new-stil)))
|
65
|
+
#f))))
|
66
|
+
|
@@ -29,14 +29,14 @@
|
|
29
29
|
|
30
30
|
<<
|
31
31
|
|
32
|
-
<% if part['settings'][:tempo] %>
|
33
|
-
\tempo "<%= part['settings'][:tempo] %>"
|
34
|
-
<% end %>
|
35
|
-
|
36
32
|
\new Staff = <%= staff_id %> \with {
|
37
33
|
}
|
38
34
|
|
39
35
|
\context Staff = <%= staff_id %> {
|
36
|
+
<% if part['settings'][:tempo] %>
|
37
|
+
\tempo "<%= part['settings'][:tempo] %>"
|
38
|
+
<% end %>
|
39
|
+
|
40
40
|
<% if score_mode %>\set Staff.instrumentName = #"<%= title %>"<% end %>
|
41
41
|
\relative c {
|
42
42
|
<% if clef %>
|
data/lib/lydown/version.rb
CHANGED
data/lib/lydown/work.rb
CHANGED
@@ -231,7 +231,7 @@ module Lydown
|
|
231
231
|
preserve_context do
|
232
232
|
process_lydown_file(entry, [
|
233
233
|
{type: :setting, key: 'part', value: part}
|
234
|
-
])
|
234
|
+
], line_range: @context[:options][:line_range])
|
235
235
|
end
|
236
236
|
end
|
237
237
|
elsif File.directory?(entry) && recursive
|
@@ -245,9 +245,47 @@ module Lydown
|
|
245
245
|
end
|
246
246
|
end
|
247
247
|
end
|
248
|
+
|
249
|
+
SKIP_ON = "\\set:\"Score.skipTypesetting = ##t\""
|
250
|
+
SHOW_BAR_NUMBERS = "\\set:\"Score.barNumberVisibility = #all-bar-numbers-visible\" |"
|
251
|
+
SKIP_OFF = "\\set:\"Score.skipTypesetting = ##f\""
|
252
|
+
|
253
|
+
HIGHLIGHT = "\\large \\override:\"NoteHead.color = #red\""
|
254
|
+
NORMAL = "\\large \\override:\"NoteHead.color = #black\""
|
255
|
+
|
256
|
+
def insert_skip_markers(content, range)
|
257
|
+
unless range.first.nil?
|
258
|
+
lines = content.lines
|
259
|
+
start = range.first - 2; start = 0 if start < 0
|
260
|
+
stop = range.last + 2; stop = lines.size if stop > lines.size
|
261
|
+
|
262
|
+
lines.insert(stop, "| #{SKIP_ON}")
|
263
|
+
lines.insert(range.last + 1, NORMAL)
|
264
|
+
if start > 0
|
265
|
+
lines.insert(range.first, HIGHLIGHT)
|
266
|
+
lines.insert(start, SHOW_BAR_NUMBERS)
|
267
|
+
lines.insert(start, NORMAL)
|
268
|
+
lines.insert(start, SKIP_OFF)
|
269
|
+
lines.insert(0, SKIP_ON)
|
270
|
+
else
|
271
|
+
lines.insert(0, SHOW_BAR_NUMBERS)
|
272
|
+
end
|
273
|
+
|
274
|
+
lines.join("\n")
|
275
|
+
else
|
276
|
+
content
|
277
|
+
end
|
278
|
+
end
|
248
279
|
|
249
|
-
def process_lydown_file(path, prefix = [])
|
250
|
-
|
280
|
+
def process_lydown_file(path, prefix = [], opts = {})
|
281
|
+
return unless File.file?(path)
|
282
|
+
|
283
|
+
content = IO.read(path)
|
284
|
+
if opts[:line_range]
|
285
|
+
content = insert_skip_markers(content, opts[:line_range])
|
286
|
+
end
|
287
|
+
|
288
|
+
process(prefix + LydownParser.parse(content))
|
251
289
|
end
|
252
290
|
end
|
253
291
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lydown
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: treetop
|
@@ -37,6 +37,8 @@ files:
|
|
37
37
|
- lib/lydown.rb
|
38
38
|
- lib/lydown/cli.rb
|
39
39
|
- lib/lydown/cli/compiler.rb
|
40
|
+
- lib/lydown/cli/diff.rb
|
41
|
+
- lib/lydown/cli/proofing.rb
|
40
42
|
- lib/lydown/core_ext.rb
|
41
43
|
- lib/lydown/errors.rb
|
42
44
|
- lib/lydown/lilypond.rb
|