lydown 0.6.5 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c68a05810e98be2fcb3b537974fca72e8ab957ee
4
- data.tar.gz: 8fb1263e28187dcb3a2a50c5d293b8f3df03adfc
3
+ metadata.gz: d8be82e654bd57692d8e882f1c8643bd684d637c
4
+ data.tar.gz: 80c45eb4a1a4c4eb26960356e01774150d0b2697
5
5
  SHA512:
6
- metadata.gz: f3def62947a128f550444aa070c4c527452af1047adabb5d50de259a9288b518fc17deef3831e5a8c8a82a10b67b6e2f932379eb5cdf67d3b43b4fc502c4f1fa
7
- data.tar.gz: 0baba95bf6967f19cddc306ea483fca59c09be0803996bc7f1b50170fd96a7de6523ae8cd32803240a9076d06992b4ba8bfbe806b5aaa449b604f6abb3984e81
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 are entered using + and -
115
+ Accidentals can be entered using + and -
116
116
 
117
- 8cgb-c2a => c8 g bb c a2
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
- 8g6fedcba2g => g8 fs16 e d c b a g2
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].nil? || 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
- # translate lydown code to lilypond code
100
- ly = ''
101
- begin
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
- if $options['format'] == 'ly'
114
- unless $options["output_filename"]
115
- puts ly
116
- exit
117
- else
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
@@ -0,0 +1,6 @@
1
+ module Lydown
2
+ module CLI
3
+ end
4
+ end
5
+
6
+ require 'lydown/cli/compiler'
@@ -1,5 +1,6 @@
1
1
  require 'lydown/errors'
2
- require 'tmpdir'
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
- ly_path = File.join(tmpdir, File.basename(opts[:output_filename]))
15
- File.open(ly_path, 'w+') do |f|
16
- f << source
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 #{File.dirname(opts[:output_filename])} "
33
+ cmd << "-o #{opts[:output_filename]} "
22
34
  cmd << "--#{opts[:format]} " if opts[:format]
23
- # cmd << '-s - 2>&1'
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 # bass 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
@@ -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
+ }
@@ -3,7 +3,7 @@ module Lydown::Rendering
3
3
  def self.movement_title(work, name)
4
4
  return nil if name.nil? || name.empty?
5
5
 
6
- if name =~ /^(?:([0-9])+([a-z]*))\-(.+)$/
6
+ if name =~ /^(?:([0-9]+)([a-z]*))\-(.+)$/
7
7
  title = "#{$1.to_i}#{$2}. #{$3.capitalize}"
8
8
  else
9
9
  title = name
@@ -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(/[\-\+]/) { |c| value += ACCIDENTAL_VALUES[c]; '' }
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 = FICTA_CODE
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 =~ /^([a-g][\+\-]*) (major|minor)$/
107
+ unless value =~ /^([A-Ga-g][\+\-#ß]*) (major|minor)$/
108
108
  raise LydownError, "Invalid key signature #{value.inspect}"
109
109
  end
110
110
 
@@ -1,3 +1,3 @@
1
1
  module Lydown
2
- VERSION = "0.6.5"
2
+ VERSION = "0.7.0"
3
3
  end
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
- unless DEFAULT_BASENAMES.include?(part)
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
- process([{type: :setting, key: 'movement', value: movement}])
237
- process_directory(entry, false)
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.6.5
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-24 00:00:00.000000000 Z
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