lydown 0.7.2 → 0.9.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 +25 -14
- data/bin/lydown +1 -122
- data/lib/lydown.rb +3 -3
- data/lib/lydown/cli.rb +4 -0
- data/lib/lydown/cli/commands.rb +98 -0
- data/lib/lydown/cli/compiler.rb +11 -14
- data/lib/lydown/cli/diff.rb +3 -3
- data/lib/lydown/cli/output.rb +18 -0
- data/lib/lydown/cli/proofing.rb +8 -6
- data/lib/lydown/cli/support.rb +34 -0
- data/lib/lydown/cli/translation.rb +73 -0
- data/lib/lydown/core_ext.rb +1 -1
- data/lib/lydown/lilypond.rb +49 -11
- data/lib/lydown/parsing.rb +37 -6
- data/lib/lydown/parsing/nodes.rb +57 -56
- data/lib/lydown/rendering.rb +0 -9
- data/lib/lydown/rendering/base.rb +2 -2
- data/lib/lydown/rendering/command.rb +2 -2
- data/lib/lydown/rendering/comments.rb +1 -1
- data/lib/lydown/rendering/figures.rb +14 -14
- data/lib/lydown/rendering/lib.ly +22 -0
- data/lib/lydown/rendering/lyrics.rb +2 -2
- data/lib/lydown/rendering/movement.rb +2 -2
- data/lib/lydown/rendering/music.rb +46 -46
- data/lib/lydown/rendering/notes.rb +149 -70
- data/lib/lydown/rendering/settings.rb +21 -16
- data/lib/lydown/rendering/skipping.rb +1 -1
- data/lib/lydown/rendering/source_ref.rb +4 -4
- data/lib/lydown/rendering/staff.rb +8 -4
- data/lib/lydown/rendering/voices.rb +9 -9
- data/lib/lydown/templates.rb +9 -0
- data/lib/lydown/templates/lilypond_doc.erb +1 -1
- data/lib/lydown/templates/movement.erb +9 -1
- data/lib/lydown/templates/part.erb +12 -3
- data/lib/lydown/translation.rb +17 -0
- data/lib/lydown/translation/ripple.rb +30 -0
- data/lib/lydown/translation/ripple/nodes.rb +191 -0
- data/lib/lydown/translation/ripple/ripple.treetop +100 -0
- data/lib/lydown/version.rb +1 -1
- data/lib/lydown/work.rb +144 -198
- data/lib/lydown/work_context.rb +152 -0
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9597286c88009e270c73fae97a968f1d946c52e2
|
4
|
+
data.tar.gz: d360df9c114bfc5fefcaf600832e549c42997232
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 603853150a584ee4951388f1565bee07aac65e36639a703d10944de9b011f6530243a9f25fe2abe037f35ce84d33c3bc11a7139fbe7ea16144c4c49662a2dcb2
|
7
|
+
data.tar.gz: 04c071237d29bdaaa0fb78becd234ae5da75fc1321cafd0901fd879b472a09aaf01713c858b9a233a29243d4fa1b62b19cd1f768f85c261eadb6b84d855e2d2a
|
data/README.md
CHANGED
@@ -97,19 +97,7 @@ Notes can be repeated using the <code>@</code> placeholder:
|
|
97
97
|
Chords are written using angled brackets, like in lilypond:
|
98
98
|
|
99
99
|
(2<fd>4<ge>) => <f d>2( <g e>4)
|
100
|
-
|
101
|
-
### Rests
|
102
|
-
|
103
|
-
Normal rests are written [like in lilypond](http://www.lilypond.org/doc/v2.18/Documentation/notation/writing-rests#rests):
|
104
|
-
|
105
|
-
4ce2r => c4 e r2
|
106
|
-
|
107
|
-
Full bar rests are [similar to lilypond](http://www.lilypond.org/doc/v2.18/Documentation/notation/writing-rests#full-measure-rests), except there's no need to enter the rest value (it is implicit in the time signature):
|
108
|
-
|
109
|
-
- time: 3/4
|
110
|
-
// 4 bar rest in the middle
|
111
|
-
2c4e R*4 2.g
|
112
|
-
|
100
|
+
|
113
101
|
### Accidentals
|
114
102
|
|
115
103
|
Accidentals can be entered using + and -
|
@@ -143,7 +131,18 @@ A ficta accidental (an non-original accidental that appears above the staff) can
|
|
143
131
|
|
144
132
|
### Octaves
|
145
133
|
|
146
|
-
|
134
|
+
In Lydown, the first note in the document carries an absolute octave marker, using the <code>'</code> and <code>,</code> signs:
|
135
|
+
|
136
|
+
c,, // contrabass octave
|
137
|
+
c, // great octave
|
138
|
+
c // small octave
|
139
|
+
c' // first octave (middle c)
|
140
|
+
c'' // second octave
|
141
|
+
c''' // third octave
|
142
|
+
... // etc.
|
143
|
+
|
144
|
+
For the following notes, the octave markers <code>'</code> and <code>,</code> are used for jumping between octaves, using the same rules as
|
145
|
+
lilypond's [relative mode](http://www.lilypond.org/doc/v2.18/Documentation/notation/writing-pitches#relative-octave-entry):
|
147
146
|
|
148
147
|
### Barlines
|
149
148
|
|
@@ -156,6 +155,18 @@ When entering unmetered music, an invisible barline can be added in order to pro
|
|
156
155
|
-time: unmetered
|
157
156
|
cdef ?| gag
|
158
157
|
|
158
|
+
### Rests
|
159
|
+
|
160
|
+
Normal rests are written [like in lilypond](http://www.lilypond.org/doc/v2.18/Documentation/notation/writing-rests#rests):
|
161
|
+
|
162
|
+
4ce2r => c4 e r2
|
163
|
+
|
164
|
+
Full bar rests are [similar to lilypond](http://www.lilypond.org/doc/v2.18/Documentation/notation/writing-rests#full-measure-rests), except there's no need to enter the rest value (it is implicit in the time signature):
|
165
|
+
|
166
|
+
- time: 3/4
|
167
|
+
// 4 bar rest in the middle
|
168
|
+
2c4e R*4 2.g
|
169
|
+
|
159
170
|
### Beams, slurs and ties
|
160
171
|
|
161
172
|
Lydown uses automatic beaming as the default, except in the case of vocal parts (see [document settings](#settings)). Auto beaming can be
|
data/bin/lydown
CHANGED
@@ -1,126 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'rubygems'
|
4
|
-
require 'lydown'
|
5
|
-
require 'lydown/version'
|
6
3
|
require 'lydown/cli'
|
7
|
-
require 'optparse'
|
8
4
|
|
9
|
-
|
10
|
-
trap("TERM") {exit}
|
11
|
-
|
12
|
-
help = <<HELP
|
13
|
-
Lydown is not lilypond
|
14
|
-
HELP
|
15
|
-
|
16
|
-
$options = {'format' => 'pdf'}.deep!
|
17
|
-
opts = OptionParser.new do |opts|
|
18
|
-
opts.banner = help
|
19
|
-
|
20
|
-
opts.on("-v", "--version", "Display current version") do
|
21
|
-
puts "lydown " + Lydown::VERSION
|
22
|
-
exit 0
|
23
|
-
end
|
24
|
-
|
25
|
-
opts.on("-p", "--parts PART", "Parts (comma-separated)") do |v|
|
26
|
-
$options[:parts] = v.split(',')
|
27
|
-
end
|
28
|
-
|
29
|
-
opts.on("-m", "--mvts MVT", "Movements (comma-separated)") do |v|
|
30
|
-
$options[:movements] = v.split(',')
|
31
|
-
end
|
32
|
-
|
33
|
-
opts.on("--no-score", "Do not generate secore") do
|
34
|
-
$options[:no_score] = true
|
35
|
-
end
|
36
|
-
|
37
|
-
opts.on("-s", "--score", "Generate only score, no parts") do
|
38
|
-
$options[:score_only] = true
|
39
|
-
end
|
40
|
-
|
41
|
-
opts.on("-V", "--vocal", "Generate only vocal score") do
|
42
|
-
$options[:vocal_only] = true
|
43
|
-
end
|
44
|
-
|
45
|
-
opts.on("--ly", "Generate Lilypond file") do
|
46
|
-
$options[:format] = 'ly'
|
47
|
-
end
|
48
|
-
|
49
|
-
opts.on("--pdf", "Generate PDF file") do
|
50
|
-
$options[:format] = 'pdf'
|
51
|
-
end
|
52
|
-
|
53
|
-
opts.on("--png", "Generate PNG file") do
|
54
|
-
$options[:format] = 'png'
|
55
|
-
end
|
56
|
-
|
57
|
-
opts.on("-M", "--midi", "Generate midi file") do
|
58
|
-
$options[:format] = 'midi'
|
59
|
-
$options[:score_only] = true # implied
|
60
|
-
end
|
61
|
-
|
62
|
-
opts.on("-P", "--proof", "Start proofing mode") do
|
63
|
-
$options[:open_target] = true
|
64
|
-
$options[:proof_mode] = true
|
65
|
-
end
|
66
|
-
|
67
|
-
opts.on("-O", "--open", "Open PDF/Midi file after processing") do
|
68
|
-
$options[:open_target] = true
|
69
|
-
end
|
70
|
-
|
71
|
-
opts.on("-o", "--output FILE", "Filename for output") do |v|
|
72
|
-
$options[:output_filename] = v
|
73
|
-
end
|
74
|
-
|
75
|
-
opts.on("-W", "--work", "Create new work") do
|
76
|
-
$options[:gen] = :work
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
opts.parse!
|
81
|
-
|
82
|
-
if $options[:gen]
|
83
|
-
# Ripple.generate($options[:gen], ARGV)
|
84
|
-
exit
|
85
|
-
end
|
86
|
-
|
87
|
-
source = ''
|
88
|
-
if ARGV[0] == '-'
|
89
|
-
# read source from stdin
|
90
|
-
source = STDIN.read
|
91
|
-
|
92
|
-
# the output defaults to a file named lydown expect if the format is ly.
|
93
|
-
# In that case the output will be sent to STDOUT.
|
94
|
-
$options[:output_filename] ||= 'lydown' unless $options[:format] == 'ly'
|
95
|
-
else
|
96
|
-
filename = ARGV[0] || '.'
|
97
|
-
$options[:source_filename] = filename
|
98
|
-
if (filename !~ /\.ld$/) and File.file?(filename + ".ld")
|
99
|
-
filename += ".ld"
|
100
|
-
end
|
101
|
-
|
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
|
109
|
-
end
|
110
|
-
|
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))
|
117
|
-
end
|
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
|
5
|
+
Lydown::CLI::Commands.start(ARGV)
|
data/lib/lydown.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
|
3
1
|
module Lydown; end
|
4
2
|
|
5
3
|
require 'lydown/core_ext'
|
@@ -8,4 +6,6 @@ require 'lydown/parsing'
|
|
8
6
|
require 'lydown/templates'
|
9
7
|
require 'lydown/rendering'
|
10
8
|
require 'lydown/lilypond'
|
11
|
-
require 'lydown/
|
9
|
+
require 'lydown/work_context'
|
10
|
+
require 'lydown/work'
|
11
|
+
require 'lydown/translation'
|
data/lib/lydown/cli.rb
CHANGED
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module Lydown::CLI
|
4
|
+
class Commands < Thor
|
5
|
+
desc "version", "show Lydown version"
|
6
|
+
def version
|
7
|
+
require 'lydown/version'
|
8
|
+
|
9
|
+
puts "Lydown version #{Lydown::VERSION}"
|
10
|
+
exit!(0)
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "compile [PATH]", "compile the lydown source at PATH"
|
14
|
+
method_option :format, aliases: '-f',
|
15
|
+
default: 'pdf', desc: 'Set output format (pdf/png/ly/midi)',
|
16
|
+
enum: %w{pdf png ly midi}
|
17
|
+
method_option :png, type: :boolean, desc: 'Set PNG output format'
|
18
|
+
method_option :ly, type: :boolean, desc: 'Set Lilypond output format'
|
19
|
+
method_option :midi, type: :boolean, desc: 'Set MIDI output format'
|
20
|
+
|
21
|
+
method_option :parts, aliases: '-p',
|
22
|
+
desc: 'Compile only the specified parts (comma separated)'
|
23
|
+
method_option :movements, aliases: '-m',
|
24
|
+
desc: 'Compile only the specified movements (comma separated)'
|
25
|
+
method_option :score_only, type: :boolean, aliases: '-s',
|
26
|
+
desc: 'Compile score only'
|
27
|
+
method_option :parts_only, type: :boolean, aliases: '-n',
|
28
|
+
desc: 'Compile parts only'
|
29
|
+
method_option :output, aliases: '-o',
|
30
|
+
desc: 'Set output path'
|
31
|
+
method_option :open_target, type: :boolean, aliases: '-O',
|
32
|
+
desc: 'Open output file after compilation'
|
33
|
+
method_option :verbose, type: :boolean
|
34
|
+
def compile(*args)
|
35
|
+
require 'lydown'
|
36
|
+
|
37
|
+
opts = Lydown::CLI::Support.copy_options(options)
|
38
|
+
opts[:path] = args.first || '.'
|
39
|
+
Lydown::CLI::Support.detect_filename(opts)
|
40
|
+
|
41
|
+
# Set format based on direct flag
|
42
|
+
[:png, :ly, :midi].each {|f| opts[:format] = f.to_s if opts[f]}
|
43
|
+
|
44
|
+
opts[:parts] = opts[:parts].split(',') if opts[:parts]
|
45
|
+
opts[:movements] = opts[:movements].split(',') if opts[:movements]
|
46
|
+
|
47
|
+
# compile score
|
48
|
+
unless opts[:parts_only] || opts[:parts]
|
49
|
+
Lydown::CLI::Compiler.process(opts.merge(mode: :score, parts: nil))
|
50
|
+
end
|
51
|
+
|
52
|
+
# compile parts
|
53
|
+
unless opts[:score_only] || !opts[:parts]
|
54
|
+
parts = opts[:parts]
|
55
|
+
parts.each do |p|
|
56
|
+
Lydown::CLI::Compiler.process(opts.merge(mode: :part, parts: p))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "proof [PATH]", "start proofing mode on source at PATH"
|
62
|
+
method_option :format, aliases: '-f',
|
63
|
+
default: 'pdf', desc: 'Set output format (pdf/png/ly)',
|
64
|
+
enum: %w{pdf png ly}
|
65
|
+
def proof(*args)
|
66
|
+
require 'lydown'
|
67
|
+
|
68
|
+
opts = Lydown::CLI::Support.copy_options(options)
|
69
|
+
opts[:path] = args.first || '.'
|
70
|
+
opts[:proof_mode] = true
|
71
|
+
opts[:open_target] = true
|
72
|
+
|
73
|
+
Lydown::CLI::Support.detect_filename(opts)
|
74
|
+
Lydown::CLI::Proofing.start_proofing(opts)
|
75
|
+
end
|
76
|
+
|
77
|
+
desc "translate [PATH]", "translate source at PATH into lydown code"
|
78
|
+
def translate(*args)
|
79
|
+
require 'lydown'
|
80
|
+
|
81
|
+
opts = Lydown::CLI::Support.copy_options(options)
|
82
|
+
opts[:path] = args.first || '.'
|
83
|
+
|
84
|
+
Lydown::CLI::Translation.process(opts)
|
85
|
+
end
|
86
|
+
|
87
|
+
def method_missing(method, *args)
|
88
|
+
args = ["compile", method.to_s] + args
|
89
|
+
self.class.start(args)
|
90
|
+
end
|
91
|
+
|
92
|
+
default_task :compile
|
93
|
+
|
94
|
+
# Allow default task with test as path (should we be doing this for other
|
95
|
+
# Object instance methods?)
|
96
|
+
undef_method(:test)
|
97
|
+
end
|
98
|
+
end
|
data/lib/lydown/cli/compiler.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'lydown'
|
2
|
-
|
3
1
|
module Lydown::CLI::Compiler
|
4
2
|
class << self
|
5
3
|
def output_filename(opts)
|
@@ -14,6 +12,7 @@ module Lydown::CLI::Compiler
|
|
14
12
|
end
|
15
13
|
|
16
14
|
def process(opts)
|
15
|
+
t1 = Time.now
|
17
16
|
opts = opts.deep_clone
|
18
17
|
# translate lydown code to lilypond code
|
19
18
|
ly_code = ''
|
@@ -23,11 +22,11 @@ module Lydown::CLI::Compiler
|
|
23
22
|
work = Lydown::Work.new(opts)
|
24
23
|
ly_code = work.to_lilypond(opts)
|
25
24
|
rescue LydownError => e
|
26
|
-
|
27
|
-
|
25
|
+
$stderr.puts e.message
|
26
|
+
$stderr.puts e.backtrace.join("\n")
|
28
27
|
exit 1
|
29
28
|
rescue => e
|
30
|
-
|
29
|
+
$stderr.puts "#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
|
31
30
|
exit 1
|
32
31
|
end
|
33
32
|
|
@@ -42,28 +41,26 @@ module Lydown::CLI::Compiler
|
|
42
41
|
f.write ly_code
|
43
42
|
end
|
44
43
|
rescue => e
|
45
|
-
|
44
|
+
$stderr.puts "#{e.class}: #{e.message}"
|
46
45
|
end
|
47
46
|
end
|
48
47
|
else
|
49
48
|
compile(ly_code, opts)
|
50
49
|
end
|
50
|
+
t2 = Time.now
|
51
|
+
$stderr.puts "Elapsed: #{'%.1f' % [t2-t1]}s"
|
51
52
|
end
|
52
53
|
|
53
54
|
def compile(ly_code, opts)
|
54
55
|
opts = opts.deep_clone
|
55
56
|
begin
|
56
|
-
STDERR.puts "Compiling => #{opts[:output_target]}"
|
57
|
-
t1 = Time.now
|
58
57
|
Lydown::Lilypond.compile(ly_code, opts)
|
59
|
-
t2 = Time.now
|
60
|
-
STDERR.puts "Elapsed: #{t2-t1}s"
|
61
58
|
rescue LydownError => e
|
62
|
-
|
63
|
-
|
59
|
+
$stderr.puts e.message
|
60
|
+
$stderr.puts e.backtrace.join("\n")
|
64
61
|
rescue => e
|
65
|
-
|
66
|
-
|
62
|
+
$stderr.puts "#{e.class}: #{e.message}"
|
63
|
+
$stderr.puts e.backtrace.join("\n")
|
67
64
|
end
|
68
65
|
|
69
66
|
if opts[:open_target]
|
data/lib/lydown/cli/diff.rb
CHANGED
@@ -18,7 +18,7 @@ module Lydown::CLI::Diff
|
|
18
18
|
set_cached_content(path, read_content(path)) rescue nil
|
19
19
|
count += 1
|
20
20
|
end
|
21
|
-
puts "Cached #{count} files."
|
21
|
+
$stderr.puts "Cached #{count} files."
|
22
22
|
end
|
23
23
|
|
24
24
|
def read_content(path)
|
@@ -47,8 +47,8 @@ module Lydown::CLI::Diff
|
|
47
47
|
|
48
48
|
first..last
|
49
49
|
rescue => e
|
50
|
-
|
51
|
-
|
50
|
+
$stderr.puts e.message
|
51
|
+
$stderr.puts e.backtrace.join("\n")
|
52
52
|
nil..nil
|
53
53
|
end
|
54
54
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'ruby-progressbar'
|
2
|
+
|
3
|
+
module Lydown::CLI
|
4
|
+
PROGRESS_FORMAT = '%t:%B:%p%%'
|
5
|
+
|
6
|
+
# Simple wrapper around ProgressBar
|
7
|
+
def self.show_progress(title, total)
|
8
|
+
$progress_bar = ProgressBar.create(
|
9
|
+
title: title,
|
10
|
+
total: total,
|
11
|
+
format: PROGRESS_FORMAT,
|
12
|
+
)
|
13
|
+
yield $progress_bar
|
14
|
+
ensure
|
15
|
+
$progress_bar.stop
|
16
|
+
$progress_bar = nil
|
17
|
+
end
|
18
|
+
end
|
data/lib/lydown/cli/proofing.rb
CHANGED
@@ -7,21 +7,23 @@ module Lydown::CLI::Proofing
|
|
7
7
|
|
8
8
|
Lydown::CLI::Diff.fill_cache(source)
|
9
9
|
|
10
|
-
puts "Proof mode: #{source} -> #{opts[:output_filename]}"
|
10
|
+
$stderr.puts "Proof mode: #{source} -> #{opts[:output_filename]}"
|
11
11
|
last_proof_path = nil
|
12
12
|
|
13
13
|
watch_directory(source, opts)
|
14
14
|
end
|
15
15
|
|
16
16
|
def watch_directory(source, opts)
|
17
|
-
dw = DirectoryWatcher.new(
|
17
|
+
dw = DirectoryWatcher.new(
|
18
|
+
File.expand_path(source),
|
19
|
+
glob: ["**/*.ld"],
|
20
|
+
pre_load: true
|
21
|
+
)
|
18
22
|
dw.interval = 0.25
|
19
|
-
dw.glob = ["#{source}/**/*.ld"]
|
20
23
|
|
21
|
-
dw.reset(true)
|
22
24
|
dw.add_observer do |*args|
|
23
25
|
args.each do |e|
|
24
|
-
if e.type
|
26
|
+
if e.type == :modified
|
25
27
|
path = File.expand_path(e.path)
|
26
28
|
if path =~ /^#{File.expand_path(source)}\/(.+)/
|
27
29
|
path = $1
|
@@ -85,7 +87,7 @@ module Lydown::CLI::Proofing
|
|
85
87
|
def process(opts)
|
86
88
|
if opts[:line_range] != (nil..nil)
|
87
89
|
t = Time.now.strftime("%H:%M:%S")
|
88
|
-
puts "[#{t}] Changed: #{opts[:base_path]} (lines #{opts[:line_range].inspect})"
|
90
|
+
$stderr.puts "[#{t}] Changed: #{opts[:base_path]} (lines #{opts[:line_range].inspect})"
|
89
91
|
Lydown::CLI::Compiler.process(opts)
|
90
92
|
end
|
91
93
|
end
|