lydown 0.6.5 → 0.7.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 +7 -3
- data/bin/lydown +16 -49
- data/lib/lydown/cli/compiler.rb +75 -0
- data/lib/lydown/cli.rb +6 -0
- data/lib/lydown/lilypond.rb +19 -7
- data/lib/lydown/parsing/lydown.treetop +3 -3
- data/lib/lydown/rendering/lib.ly +17 -0
- data/lib/lydown/rendering/movement.rb +1 -1
- data/lib/lydown/rendering/notes.rb +17 -10
- data/lib/lydown/rendering/settings.rb +2 -2
- data/lib/lydown/version.rb +1 -1
- data/lib/lydown/work.rb +13 -7
- 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: d8be82e654bd57692d8e882f1c8643bd684d637c
|
4
|
+
data.tar.gz: 80c45eb4a1a4c4eb26960356e01774150d0b2697
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 755759c7dbc352e537743f8b829f35791297baa586a89a2e80cbd6fd98aef6a48cd54bb8f2d7c26c1aa8a4568701c69d5fdf117d56a271e9a1aebdf24aecbf0c
|
7
|
+
data.tar.gz: e5e151f5f78d6b372ca5cf655aeba53dc68be083d6b34b160b0211c89a9c6765498db2878f093ebd7d3e1c9fdac9d3bd2da11ee955c43b768b944f72e81d9f8f
|
data/README.md
CHANGED
@@ -112,14 +112,18 @@ Full bar rests are [similar to lilypond](http://www.lilypond.org/doc/v2.18/Docum
|
|
112
112
|
|
113
113
|
### Accidentals
|
114
114
|
|
115
|
-
Accidentals
|
115
|
+
Accidentals can be entered using + and -
|
116
116
|
|
117
|
-
8cgb-c2a => c8 g
|
117
|
+
8cgb-c2a => c8 g bes c a2
|
118
|
+
|
119
|
+
But can also be entered using the characters # for sharp, ß for flat and h for natural:
|
120
|
+
|
121
|
+
c#dßeh => cis des e
|
118
122
|
|
119
123
|
In lydown notes follow the key signature by default:
|
120
124
|
|
121
125
|
- key: g major
|
122
|
-
|
126
|
+
ff#fhfßd#bß => fis fisis f f dis bes
|
123
127
|
|
124
128
|
The accidental mode can be changed by specifiying the manual accidental mode:
|
125
129
|
|
data/bin/lydown
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'lydown'
|
5
5
|
require 'lydown/version'
|
6
|
+
require 'lydown/cli'
|
6
7
|
require 'optparse'
|
7
8
|
|
8
9
|
trap("INT") {exit}
|
@@ -58,6 +59,10 @@ opts = OptionParser.new do |opts|
|
|
58
59
|
$options["score_only"] = true # implied
|
59
60
|
end
|
60
61
|
|
62
|
+
opts.on("-P", "--proof", "Start proofing mode") do
|
63
|
+
$options["proof_mode"] = true
|
64
|
+
end
|
65
|
+
|
61
66
|
opts.on("-O", "--open", "Open PDF/Midi file after processing") do
|
62
67
|
$options["open_target"] = true
|
63
68
|
end
|
@@ -72,6 +77,7 @@ opts = OptionParser.new do |opts|
|
|
72
77
|
end
|
73
78
|
|
74
79
|
opts.parse!
|
80
|
+
$options.deep!
|
75
81
|
|
76
82
|
if $options["gen"]
|
77
83
|
# Ripple.generate($options["gen"], ARGV)
|
@@ -79,7 +85,7 @@ if $options["gen"]
|
|
79
85
|
end
|
80
86
|
|
81
87
|
source = ''
|
82
|
-
if ARGV[0]
|
88
|
+
if ARGV[0] == '-'
|
83
89
|
# read source from stdin
|
84
90
|
source = STDIN.read
|
85
91
|
|
@@ -87,7 +93,7 @@ if ARGV[0].nil? || ARGV[0] == '-'
|
|
87
93
|
# In that case the output will be sent to STDOUT.
|
88
94
|
$options["output_filename"] ||= 'lydown' unless $options["format"] == 'ly'
|
89
95
|
else
|
90
|
-
filename = ARGV[0]
|
96
|
+
filename = ARGV[0] || '.'
|
91
97
|
$options['source_filename'] = filename
|
92
98
|
if (filename !~ /\.ld$/) and File.file?(filename + ".ld")
|
93
99
|
filename += ".ld"
|
@@ -96,54 +102,15 @@ else
|
|
96
102
|
$options["output_filename"] ||= (filename =~ /^(.+)\.ld$/) ? $1 : filename
|
97
103
|
end
|
98
104
|
|
99
|
-
#
|
100
|
-
|
101
|
-
|
102
|
-
work = Lydown::Work.new(path: $options['source_filename'], nice_error: true)
|
103
|
-
# work.process(lydown)
|
104
|
-
ly = work.to_lilypond(mode: :score)
|
105
|
-
rescue LydownError => e
|
106
|
-
STDERR.puts e.message
|
107
|
-
exit 1
|
108
|
-
rescue => e
|
109
|
-
STDERR.puts "#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
|
110
|
-
exit 1
|
105
|
+
# compile score
|
106
|
+
unless $options[:no_score] || $options[:parts]
|
107
|
+
Lydown::CLI::Compiler.process($options.merge(mode: :score, parts: nil))
|
111
108
|
end
|
112
109
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
begin
|
119
|
-
File.open($options["output_filename"] + '.ly', 'w+') do |f|
|
120
|
-
f.write ly
|
121
|
-
end
|
122
|
-
exit
|
123
|
-
rescue => e
|
124
|
-
STDERR.puts "#{e.class}: #{e.message}"
|
125
|
-
exit 1
|
126
|
-
end
|
110
|
+
# compile parts
|
111
|
+
unless $options[:score_only] || !$options[:parts]
|
112
|
+
parts = $options[:parts]
|
113
|
+
parts.each do |p|
|
114
|
+
Lydown::CLI::Compiler.process($options.merge(mode: :part, parts: p))
|
127
115
|
end
|
128
116
|
end
|
129
|
-
|
130
|
-
# compile lilypond code
|
131
|
-
begin
|
132
|
-
opts = {
|
133
|
-
output_filename: $options['output_filename'],
|
134
|
-
format: $options['format'],
|
135
|
-
mode: :score
|
136
|
-
}
|
137
|
-
Lydown::Lilypond.compile(ly, opts)
|
138
|
-
rescue LydownError => e
|
139
|
-
STDERR.puts e.message
|
140
|
-
exit 1
|
141
|
-
rescue => e
|
142
|
-
STDERR.puts "#{e.class}: #{e.message}"
|
143
|
-
exit 1
|
144
|
-
end
|
145
|
-
|
146
|
-
if $options['open_target']
|
147
|
-
filename = "#{$options['output_filename']}.#{$options['format']}"
|
148
|
-
system("open #{filename}")
|
149
|
-
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'lydown'
|
2
|
+
|
3
|
+
module Lydown::CLI::Compiler
|
4
|
+
class << self
|
5
|
+
def output_filename(opts)
|
6
|
+
fn = opts[:output_filename]
|
7
|
+
if opts[:movements] && opts[:movements].size == 1
|
8
|
+
fn << "-#{opts[:movements].first}"
|
9
|
+
end
|
10
|
+
if opts[:parts] && opts[:parts].size == 1
|
11
|
+
fn << "-#{opts[:parts].first}"
|
12
|
+
end
|
13
|
+
fn
|
14
|
+
end
|
15
|
+
|
16
|
+
def process(opts)
|
17
|
+
opts = opts.deep_clone
|
18
|
+
# translate lydown code to lilypond code
|
19
|
+
ly_code = ''
|
20
|
+
begin
|
21
|
+
opts[:path] = opts[:source_filename]
|
22
|
+
opts[:nice_error] = true
|
23
|
+
work = Lydown::Work.new(opts)
|
24
|
+
ly_code = work.to_lilypond(opts)
|
25
|
+
rescue LydownError => e
|
26
|
+
STDERR.puts e.message
|
27
|
+
STDERR.puts e.backtrace.join("\n")
|
28
|
+
exit 1
|
29
|
+
rescue => e
|
30
|
+
STDERR.puts "#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
|
34
|
+
opts[:output_target] = output_filename(opts)
|
35
|
+
|
36
|
+
if opts[:format] == 'ly'
|
37
|
+
unless opts[:output_target]
|
38
|
+
STDOUT << ly_code
|
39
|
+
else
|
40
|
+
begin
|
41
|
+
File.open(opts[:output_target] + '.ly', 'w+') do |f|
|
42
|
+
f.write ly_code
|
43
|
+
end
|
44
|
+
rescue => e
|
45
|
+
STDERR.puts "#{e.class}: #{e.message}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
else
|
49
|
+
compile(ly_code, opts)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def compile(ly_code, opts)
|
54
|
+
opts = opts.deep_clone
|
55
|
+
begin
|
56
|
+
STDERR.puts "Compiling => #{opts[:output_target]}"
|
57
|
+
t1 = Time.now
|
58
|
+
Lydown::Lilypond.compile(ly_code, opts)
|
59
|
+
t2 = Time.now
|
60
|
+
STDERR.puts "Elapsed: #{t2-t1}s"
|
61
|
+
rescue LydownError => e
|
62
|
+
STDERR.puts e.message
|
63
|
+
STDERR.puts e.backtrace.join("\n")
|
64
|
+
rescue => e
|
65
|
+
STDERR.puts "#{e.class}: #{e.message}"
|
66
|
+
STDERR.puts e.backtrace.join("\n")
|
67
|
+
end
|
68
|
+
|
69
|
+
if opts[:open_target]
|
70
|
+
filename = "#{opts[:output_target]}.#{opts[:format]}"
|
71
|
+
system("open #{filename}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/lydown/cli.rb
ADDED
data/lib/lydown/lilypond.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'lydown/errors'
|
2
|
-
require '
|
2
|
+
require 'tempfile'
|
3
|
+
require 'fileutils'
|
3
4
|
|
4
5
|
module Lydown
|
5
6
|
module Lilypond
|
@@ -11,17 +12,28 @@ module Lydown
|
|
11
12
|
def compile(source, opts = {})
|
12
13
|
opts[:output_filename] ||= 'lydown'
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
15
|
+
target = opts[:output_filename].dup
|
16
|
+
ext = ".#{opts[:format] || 'pdf'}"
|
17
|
+
if target !~ /#{ext}$/
|
18
|
+
target << ext
|
17
19
|
end
|
18
20
|
|
21
|
+
tmp_target = Tempfile.new('lydown').path
|
22
|
+
opts[:output_filename] = tmp_target
|
23
|
+
invoke(source, opts)
|
24
|
+
FileUtils.cp(tmp_target + ext, target)
|
25
|
+
rescue => e
|
26
|
+
puts e.message
|
27
|
+
p e.backtrace
|
28
|
+
end
|
29
|
+
|
30
|
+
def invoke(source, opts = {})
|
19
31
|
# Run lilypond, pipe source into its STDIN, and capture its STDERR
|
20
32
|
cmd = 'lilypond -lERROR '
|
21
|
-
cmd << "-o #{
|
33
|
+
cmd << "-o #{opts[:output_filename]} "
|
22
34
|
cmd << "--#{opts[:format]} " if opts[:format]
|
23
|
-
|
24
|
-
cmd << "-s #{ly_path} 2>&1"
|
35
|
+
cmd << '-s - 2>&1'
|
36
|
+
# cmd << "-s #{ly_path} 2>&1"
|
25
37
|
|
26
38
|
err_info = ''
|
27
39
|
IO.popen(cmd, 'r+') do |f|
|
@@ -110,7 +110,7 @@ grammar Lydown
|
|
110
110
|
rule string
|
111
111
|
'"' ('\"' / !'"' .)* '"'
|
112
112
|
end
|
113
|
-
rule figures
|
113
|
+
rule figures
|
114
114
|
'<' figures_component? (white_space? figures_component)* '>'
|
115
115
|
end
|
116
116
|
rule figures_component
|
@@ -132,13 +132,13 @@ grammar Lydown
|
|
132
132
|
[a-g@] octave* accidental* <Note::Head>
|
133
133
|
end
|
134
134
|
rule accidental
|
135
|
-
[
|
135
|
+
[\+\-#ßh]+
|
136
136
|
end
|
137
137
|
rule octave
|
138
138
|
[\,']+ <Note::Octave>
|
139
139
|
end
|
140
140
|
rule accidental_flag
|
141
|
-
[\!\?\^] <Note::AccidentalFlag>
|
141
|
+
[\!\?\^]+ <Note::AccidentalFlag>
|
142
142
|
end
|
143
143
|
rule phrasing
|
144
144
|
beam_open / beam_close / slur_open / slur_close
|
data/lib/lydown/rendering/lib.ly
CHANGED
@@ -30,3 +30,20 @@ dalsegnoadlib = {
|
|
30
30
|
\once \override Score.RehearsalMark #'font-size = #-2
|
31
31
|
\mark \markup { \musicglyph #"scripts.segno" ad lib }
|
32
32
|
}
|
33
|
+
|
34
|
+
editF = \markup { \center-align \concat { \bold { \italic ( }
|
35
|
+
\dynamic f \bold { \italic ) } } }
|
36
|
+
editP = \markup { \center-align \concat { \bold { \italic ( }
|
37
|
+
\dynamic p \bold { \italic ) } } }
|
38
|
+
editPP = \markup { \center-align \concat { \bold { \italic ( }
|
39
|
+
\dynamic pp \bold { \italic ) } } }
|
40
|
+
|
41
|
+
doux = \markup { \center-align \bold { \italic doux }}
|
42
|
+
fort = \markup { \center-align \bold { \italic fort }}
|
43
|
+
|
44
|
+
ten = \markup { \italic ten. }
|
45
|
+
|
46
|
+
ficta = {
|
47
|
+
\once \override AccidentalSuggestion #'avoid-slur = #'outside
|
48
|
+
\once \set suggestAccidentals = ##t
|
49
|
+
}
|
@@ -11,7 +11,13 @@ module Lydown::Rendering
|
|
11
11
|
KEY_ACCIDENTALS[signature] ||= calc_accidentals_for_key_signature(signature)
|
12
12
|
end
|
13
13
|
|
14
|
+
SIGNATURE_ACCIDENTAL_TRANSLATION = {
|
15
|
+
'#' => '+',
|
16
|
+
'ß' => '-'
|
17
|
+
}
|
18
|
+
|
14
19
|
def self.calc_accidentals_for_key_signature(signature)
|
20
|
+
signature = signature.gsub(/[#ß]/) {|c| SIGNATURE_ACCIDENTAL_TRANSLATION[c]}
|
15
21
|
unless signature =~ /^([a-g][\+\-]*) (major|minor)$/
|
16
22
|
raise "Invalid key signature #{signature.inspect}"
|
17
23
|
end
|
@@ -35,13 +41,19 @@ module Lydown::Rendering
|
|
35
41
|
|
36
42
|
ACCIDENTAL_VALUES = {
|
37
43
|
'+' => 1,
|
38
|
-
'-' => -1
|
44
|
+
'-' => -1,
|
45
|
+
'#' => 1,
|
46
|
+
'ß' => -1
|
39
47
|
}
|
40
48
|
|
41
49
|
def self.lilypond_note_name(note, key_signature = 'c major')
|
50
|
+
# if the natural sign (h) is used, no need to calculate the note name
|
51
|
+
return $1 if note =~ /([a-g])h/
|
52
|
+
|
42
53
|
value = 0
|
43
54
|
# accidental value from note
|
44
|
-
note = note.gsub(/[
|
55
|
+
note = note.gsub(/[\-\+#ß]/) { |c| value += ACCIDENTAL_VALUES[c]; '' }
|
56
|
+
|
45
57
|
# add key signature value
|
46
58
|
value += accidentals_for_key_signature(key_signature)[note] || 0
|
47
59
|
|
@@ -131,19 +143,14 @@ module Lydown::Rendering
|
|
131
143
|
@work.emit(event[:stream] || :music, lilypond_chord(event, notes, options))
|
132
144
|
end
|
133
145
|
|
134
|
-
FICTA_CODE = <<EOF
|
135
|
-
\\once \\override AccidentalSuggestion #'avoid-slur = #'outside
|
136
|
-
\\once \\set suggestAccidentals = ##t
|
137
|
-
EOF
|
138
|
-
|
139
146
|
def lilypond_note(event, options = {})
|
140
147
|
head = Accidentals.translate_note_name(@work, event[:head])
|
141
148
|
if options[:head_only]
|
142
149
|
head
|
143
150
|
else
|
144
|
-
if event[:accidental_flag]
|
145
|
-
accidental_flag = ''
|
146
|
-
prefix =
|
151
|
+
if event[:accidental_flag] =~ /\^/
|
152
|
+
accidental_flag = event[:accidental_flag].gsub('^', '')
|
153
|
+
prefix = '\ficta '
|
147
154
|
else
|
148
155
|
accidental_flag = event[:accidental_flag]
|
149
156
|
prefix = ''
|
@@ -69,7 +69,7 @@ module Lydown::Rendering
|
|
69
69
|
def check_setting_value(key, value)
|
70
70
|
if key == 'key'
|
71
71
|
# process shorthand notation
|
72
|
-
if value =~ /^([a-gA-G])[
|
72
|
+
if value =~ /^([a-gA-G])[\+\-#ß]*$/
|
73
73
|
mode = $1.downcase == $1 ? 'minor' : 'major'
|
74
74
|
value = "#{value.downcase} #{mode}"
|
75
75
|
end
|
@@ -104,7 +104,7 @@ module Lydown::Rendering
|
|
104
104
|
e = next_event
|
105
105
|
return if e && (e[:type] == :setting) && (e[:key] == 'key')
|
106
106
|
|
107
|
-
unless value =~ /^([
|
107
|
+
unless value =~ /^([A-Ga-g][\+\-#ß]*) (major|minor)$/
|
108
108
|
raise LydownError, "Invalid key signature #{value.inspect}"
|
109
109
|
end
|
110
110
|
|
data/lib/lydown/version.rb
CHANGED
data/lib/lydown/work.rb
CHANGED
@@ -18,8 +18,7 @@ module Lydown
|
|
18
18
|
def initialize(opts = {})
|
19
19
|
@context = {}.deep!
|
20
20
|
reset_context(:work)
|
21
|
-
|
22
|
-
opts.each {|k, v| @context[k] = v}
|
21
|
+
@context[:options] = opts.deep_clone
|
23
22
|
|
24
23
|
process_work_files if opts[:path]
|
25
24
|
end
|
@@ -199,7 +198,7 @@ module Lydown
|
|
199
198
|
end
|
200
199
|
|
201
200
|
def process_work_files
|
202
|
-
path = @context[:path]
|
201
|
+
path = @context[:options][:path]
|
203
202
|
path += '.ld' if File.file?(path + '.ld')
|
204
203
|
|
205
204
|
if File.file?(path)
|
@@ -219,12 +218,16 @@ module Lydown
|
|
219
218
|
process_lydown_file(File.join(path, 'work.ld'))
|
220
219
|
# process movement specific code
|
221
220
|
process_lydown_file(File.join(path, 'movement.ld'))
|
222
|
-
|
221
|
+
|
222
|
+
part_filter = @context[:options][:parts]
|
223
|
+
mvmt_filter = @context[:options][:movements]
|
224
|
+
|
223
225
|
# Iterate over sorted directory entries
|
224
226
|
Dir["#{path}/*"].entries.sort.each do |entry|
|
225
227
|
if File.file?(entry) && (entry =~ /\.ld$/)
|
226
228
|
part = File.basename(entry, '.*')
|
227
|
-
|
229
|
+
skip = part_filter && !part_filter.include?(part)
|
230
|
+
unless DEFAULT_BASENAMES.include?(part) || skip
|
228
231
|
preserve_context do
|
229
232
|
process_lydown_file(entry, [
|
230
233
|
{type: :setting, key: 'part', value: part}
|
@@ -233,8 +236,11 @@ module Lydown
|
|
233
236
|
end
|
234
237
|
elsif File.directory?(entry) && recursive
|
235
238
|
movement = File.basename(entry)
|
236
|
-
|
237
|
-
|
239
|
+
skip = mvmt_filter && !mvmt_filter.include?(movement)
|
240
|
+
unless skip
|
241
|
+
process([{type: :setting, key: 'movement', value: movement}])
|
242
|
+
process_directory(entry, false)
|
243
|
+
end
|
238
244
|
end
|
239
245
|
end
|
240
246
|
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.
|
4
|
+
version: 0.7.0
|
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-06-
|
11
|
+
date: 2015-06-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: treetop
|
@@ -35,6 +35,8 @@ files:
|
|
35
35
|
- README.md
|
36
36
|
- bin/lydown
|
37
37
|
- lib/lydown.rb
|
38
|
+
- lib/lydown/cli.rb
|
39
|
+
- lib/lydown/cli/compiler.rb
|
38
40
|
- lib/lydown/core_ext.rb
|
39
41
|
- lib/lydown/errors.rb
|
40
42
|
- lib/lydown/lilypond.rb
|