lydown 0.7.2 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|