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 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