lydown 0.7.2 → 0.9.0

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