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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -14
  3. data/bin/lydown +1 -122
  4. data/lib/lydown.rb +3 -3
  5. data/lib/lydown/cli.rb +4 -0
  6. data/lib/lydown/cli/commands.rb +98 -0
  7. data/lib/lydown/cli/compiler.rb +11 -14
  8. data/lib/lydown/cli/diff.rb +3 -3
  9. data/lib/lydown/cli/output.rb +18 -0
  10. data/lib/lydown/cli/proofing.rb +8 -6
  11. data/lib/lydown/cli/support.rb +34 -0
  12. data/lib/lydown/cli/translation.rb +73 -0
  13. data/lib/lydown/core_ext.rb +1 -1
  14. data/lib/lydown/lilypond.rb +49 -11
  15. data/lib/lydown/parsing.rb +37 -6
  16. data/lib/lydown/parsing/nodes.rb +57 -56
  17. data/lib/lydown/rendering.rb +0 -9
  18. data/lib/lydown/rendering/base.rb +2 -2
  19. data/lib/lydown/rendering/command.rb +2 -2
  20. data/lib/lydown/rendering/comments.rb +1 -1
  21. data/lib/lydown/rendering/figures.rb +14 -14
  22. data/lib/lydown/rendering/lib.ly +22 -0
  23. data/lib/lydown/rendering/lyrics.rb +2 -2
  24. data/lib/lydown/rendering/movement.rb +2 -2
  25. data/lib/lydown/rendering/music.rb +46 -46
  26. data/lib/lydown/rendering/notes.rb +149 -70
  27. data/lib/lydown/rendering/settings.rb +21 -16
  28. data/lib/lydown/rendering/skipping.rb +1 -1
  29. data/lib/lydown/rendering/source_ref.rb +4 -4
  30. data/lib/lydown/rendering/staff.rb +8 -4
  31. data/lib/lydown/rendering/voices.rb +9 -9
  32. data/lib/lydown/templates.rb +9 -0
  33. data/lib/lydown/templates/lilypond_doc.erb +1 -1
  34. data/lib/lydown/templates/movement.erb +9 -1
  35. data/lib/lydown/templates/part.erb +12 -3
  36. data/lib/lydown/translation.rb +17 -0
  37. data/lib/lydown/translation/ripple.rb +30 -0
  38. data/lib/lydown/translation/ripple/nodes.rb +191 -0
  39. data/lib/lydown/translation/ripple/ripple.treetop +100 -0
  40. data/lib/lydown/version.rb +1 -1
  41. data/lib/lydown/work.rb +144 -198
  42. data/lib/lydown/work_context.rb +152 -0
  43. metadata +11 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2945708b90bba8a47e9c037ed6b58feee552c411
4
- data.tar.gz: 3fab488b2070abaa55eccd5a2d1ee2af496419af
3
+ metadata.gz: 9597286c88009e270c73fae97a968f1d946c52e2
4
+ data.tar.gz: d360df9c114bfc5fefcaf600832e549c42997232
5
5
  SHA512:
6
- metadata.gz: c9a16ab91b2118d2ceed5791caa10319fac63e38bd09da38e19fb57ba52ab5ad6b3db857c811211a0e8f5d167d0f0e5b841aee06f0bb607df4cdba0cbd794b97
7
- data.tar.gz: 25df40e9a348873a1da26969c8f8275e7f806ff4f5386657c3a1eba4acdbd7d84f4c687eb5653867973dd656acf4b9eeb59a4ce9e9da9d73894d09a609ae7123
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
- Like in lilypond's [relative mode](http://www.lilypond.org/doc/v2.18/Documentation/notation/writing-pitches#relative-octave-entry), lydown uses ' and , for moving between octaves. The starting point is always c (that is c°).
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
- trap("INT") {exit}
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)
@@ -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/work'
9
+ require 'lydown/work_context'
10
+ require 'lydown/work'
11
+ require 'lydown/translation'
@@ -3,6 +3,10 @@ module Lydown
3
3
  end
4
4
  end
5
5
 
6
+ require 'lydown/cli/support'
6
7
  require 'lydown/cli/compiler'
7
8
  require 'lydown/cli/proofing'
8
9
  require 'lydown/cli/diff'
10
+ require 'lydown/cli/translation'
11
+ require 'lydown/cli/output'
12
+ require 'lydown/cli/commands'
@@ -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
@@ -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
- STDERR.puts e.message
27
- STDERR.puts e.backtrace.join("\n")
25
+ $stderr.puts e.message
26
+ $stderr.puts e.backtrace.join("\n")
28
27
  exit 1
29
28
  rescue => e
30
- STDERR.puts "#{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
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
- STDERR.puts "#{e.class}: #{e.message}"
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
- STDERR.puts e.message
63
- STDERR.puts e.backtrace.join("\n")
59
+ $stderr.puts e.message
60
+ $stderr.puts e.backtrace.join("\n")
64
61
  rescue => e
65
- STDERR.puts "#{e.class}: #{e.message}"
66
- STDERR.puts e.backtrace.join("\n")
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]
@@ -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
- STDERR << e.message
51
- STDERR << e.backtrace.join("\n")
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
@@ -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(File.expand_path(source))
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 = :modified
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