lygre 0.0.1 → 0.0.2

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: 526592f951e4b589a6c55ddcbdee18ef7316fe81
4
- data.tar.gz: 41375a347f0b43ebd94eb7d48b7eec8136b06870
3
+ metadata.gz: c100850289adec3dc56f49db675050c9363706e0
4
+ data.tar.gz: a47121a23251de440329e1866dbacb532dd07152
5
5
  SHA512:
6
- metadata.gz: be30c1c2c467349f386da0be4838753acd35b0b7769420a6752b36cd48046ed72c9bf71dd38077500016cd162d7621b0bfaa787da2d31107c01a3c879ba1caf1
7
- data.tar.gz: 61b8761522c20c47a2c41d445a255fd1dfb344fbced567bee020b0aefe6f3c8c526f79beb6df06b0858a478861f7c927b95366df1d4512321aea9c2160202f18
6
+ metadata.gz: 38b9473ca607f631bd91e10138d5492bb5b72e4ecaceab71d70c13ee7bc8caa521e494f2b1f30889c81412e495dfdf1eae144539982b1e56af80315453fb9d10
7
+ data.tar.gz: f697b60699d01c32a0eeb2150351e4765357fbba409917a940b7c1c421a37bf90c4061c1b38a83661412ccf3b336054ca7f269f5fc2c6727cbd1da666b3ffeb9
data/bin/grely.rb CHANGED
@@ -2,36 +2,38 @@
2
2
 
3
3
  # grely
4
4
 
5
- # one day it will perform
6
- # conversion gregorio (gabc) -> lilypond
7
-
8
- # now it only
9
- # says if it is able to parse the given input file
5
+ # converts gabc to lilypond
10
6
 
11
7
  require 'grely'
12
8
 
13
- parser = GabcParser.new
14
-
15
- if ARGV.size >= 1 then
16
- inputf = ARGV[0]
17
- rf = File.open inputf
18
- else
19
- rf = STDIN
9
+ def grely(rf)
10
+ input = rf.read
11
+
12
+ parser = GabcParser.new
13
+ result = parser.parse(input)
14
+
15
+ if result then
16
+ puts LilypondConvertor.new(cadenza: true).convert result.create_score
17
+ return true
18
+ else
19
+ STDERR.puts 'grely considers the input invalid gabc:'
20
+ STDERR.puts
21
+ STDERR.puts "'#{parser.failure_reason}' on line #{parser.failure_line} column #{parser.failure_column}:"
22
+ STDERR.puts input.split("\n")[parser.failure_line-1]
23
+ STDERR.puts (" " * parser.failure_column) + "^"
24
+ return false
25
+ end
20
26
  end
21
27
 
22
- input = rf.read
23
-
24
- result = parser.parse(input)
25
-
26
- if result then
27
- STDERR.puts 'grely thinks this is a valid gabc file.'
28
- puts LilypondConvertor.new(cadenza: true).convert result.create_score
29
- exit 0
28
+ ok = true
29
+ if ARGV.size < 1 then
30
+ grely STDIN
30
31
  else
31
- STDERR.puts 'grely considers the input invalid gabc:'
32
- STDERR.puts
33
- STDERR.puts "'#{parser.failure_reason}' on line #{parser.failure_line} column #{parser.failure_column}:"
34
- STDERR.puts input.split("\n")[parser.failure_line-1]
35
- STDERR.puts (" " * parser.failure_column) + "^"
36
- exit 1
32
+ ARGV.each do |f|
33
+ File.open(f) do |rf|
34
+ ok &&= grely rf
35
+ end
36
+ end
37
37
  end
38
+
39
+ exit ok ? 0 : 1
@@ -0,0 +1,239 @@
1
+ # Treetop grammar for gabc (input format of Gregorio).
2
+ # Compiled by Treetop emits GabcParser class.
3
+
4
+ grammar Gabc
5
+
6
+ rule score
7
+ header
8
+ header_delimiter
9
+ body
10
+ <ScoreNode>
11
+ end
12
+
13
+ # header ----------------------------
14
+
15
+ rule header
16
+ ( header_field?
17
+ inline_whitespace?
18
+ comment?
19
+ "\n" )*
20
+ <HeaderNode>
21
+ end
22
+
23
+ rule inline_whitespace
24
+ (" " / "\t")+
25
+ end
26
+
27
+ rule any_whitespace
28
+ (inline_whitespace / "\n")+
29
+ end
30
+
31
+ rule header_field
32
+ field_id
33
+ ":"
34
+ inline_whitespace?
35
+ field_value
36
+ ";" ..2
37
+ <HeaderFieldNode>
38
+ end
39
+
40
+ rule field_id
41
+ [\w-]+
42
+ end
43
+
44
+ rule field_value
45
+ (
46
+ [^;] /
47
+ (";" !(inline_whitespace? comment? "\n"))
48
+ )*
49
+ end
50
+
51
+ rule comment
52
+ "%" !"%" [^\n]*
53
+ end
54
+
55
+ rule header_delimiter
56
+ "%%\n"
57
+ end
58
+
59
+ # body ------------------------------
60
+
61
+ rule body
62
+ any_whitespace?
63
+ ( ( comment any_whitespace? ) /
64
+ ( music_word any_whitespace? comment? any_whitespace? ) )*
65
+ music_word?
66
+ <BodyNode>
67
+ end
68
+
69
+ rule clef_standalone
70
+ "(" clef ")"
71
+ end
72
+
73
+ rule clef
74
+ clef_symbol bemol:"b"? line_number <ClefNode>
75
+ end
76
+
77
+ rule clef_symbol
78
+ "c" / "f"
79
+ end
80
+
81
+ rule line_number
82
+ [1-4]
83
+ end
84
+
85
+ rule music_word
86
+ music_syllable+ <WordNode>
87
+ end
88
+
89
+ rule music_syllable
90
+ lyrics:lyrics_syllable? music <SyllableNode>
91
+ end
92
+
93
+ rule lyrics_syllable
94
+ word_character+
95
+ ( any_whitespace
96
+ word_character+
97
+ )*
98
+ any_whitespace?
99
+ end
100
+
101
+ rule word_character
102
+ guillemets / special_word_character / formatted_characters / text_above_lines / regular_word_character
103
+ end
104
+
105
+ rule regular_word_character
106
+ [^\(\n\t ] # anything but: opening parentheses, newline, tab, space
107
+ end
108
+
109
+ rule special_word_character
110
+ "<sp>" (regular_word_character / parentheses)+ "</sp>"
111
+ end
112
+
113
+ # this rule doesn't handle tag mismatch.
114
+ # However, for purposes of gabc->lilypond convertor
115
+ # such an issue may be safely ignored.
116
+ rule formatted_characters
117
+ "<" formatting_tag ">"
118
+ ( regular_word_character / special_word_character / inline_whitespace / formatted_characters / parentheses )+
119
+ "</" formatting_tag ">"
120
+ end
121
+
122
+ rule formatting_tag
123
+ "b" / "i" / "sc" / "v"
124
+ end
125
+
126
+ rule text_above_lines
127
+ "<alt>"
128
+ ( regular_word_character / inline_whitespace )+
129
+ "</alt>"
130
+ end
131
+
132
+ rule parentheses
133
+ [\(\)]
134
+ end
135
+
136
+ rule guillemets
137
+ "<<" / ">>"
138
+ end
139
+
140
+ rule music
141
+ "(" notes? neumes? ")"
142
+ end
143
+
144
+ rule notes
145
+ ( clef / guide / alteration / (note choral_sign? brace?) / space / custos / linebreak / divisio / macro / text_above_lines_in_music )+
146
+ end
147
+
148
+ rule note
149
+ initio_debilis? note_pitch shape_modifiers? rhythmic_sign* accent?
150
+ <NoteNode>
151
+ end
152
+
153
+ rule note_pitch
154
+ simple_pitch / punctum_inclinatum_pitch
155
+ end
156
+
157
+ # used not only in notes
158
+ rule simple_pitch
159
+ [a-m]
160
+ end
161
+
162
+ rule punctum_inclinatum_pitch
163
+ [A-M]
164
+ end
165
+
166
+ rule initio_debilis
167
+ "-"
168
+ end
169
+
170
+ rule shape_modifiers
171
+ ( [oOVwWqR] / "v"+ / "s"+ / ([r] "0"? ![1-5]) )? [~<>]?
172
+ end
173
+
174
+ rule rhythmic_sign
175
+ "." / ("'" above_below?) / ("_" episema_modifiers?)
176
+ end
177
+
178
+ rule above_below
179
+ [01]
180
+ end
181
+
182
+ rule episema_modifiers
183
+ [0-5] ..3
184
+ end
185
+
186
+ rule accent
187
+ "r" [1-5]
188
+ end
189
+
190
+ rule space
191
+ ( "!"? ( ("/" "/"?) / " " ) ) /
192
+ "!"
193
+ end
194
+
195
+ rule linebreak
196
+ [zZ]
197
+ end
198
+
199
+ rule custos
200
+ "z0"
201
+ end
202
+
203
+ # ~ custos at the end of a score
204
+ rule guide
205
+ simple_pitch "+"
206
+ end
207
+
208
+ rule alteration
209
+ simple_pitch [xy\#]
210
+ end
211
+
212
+ rule divisio
213
+ (( "," "_"? ) /
214
+ "`" /
215
+ ( ";" [1-6]? ) /
216
+ ( ":" (":" / "'")? ))
217
+ <DivisioNode>
218
+ end
219
+
220
+ rule choral_sign
221
+ "[cs:" [^\]]+ "]"
222
+ end
223
+
224
+ rule brace
225
+ "[o" "c"? "b" "a"? ":" [^\]]+ "]"
226
+ end
227
+
228
+ rule macro
229
+ "[" [nge] "m" [0-9] "]"
230
+ end
231
+
232
+ rule text_above_lines_in_music
233
+ "[alt:" [^\]]* "]"
234
+ end
235
+
236
+ rule neumes
237
+ "|" [^\)]*
238
+ end
239
+ end
@@ -31,8 +31,6 @@ end
31
31
 
32
32
  class GabcMusic < Immutable
33
33
 
34
- attr_accessor :clef
35
-
36
34
  # Array of GabcWords
37
35
  attr_accessor :words
38
36
  end
@@ -38,11 +38,9 @@ module Gabc
38
38
  r = {}
39
39
 
40
40
  each_element do |lvl1|
41
- lvl1.each_element do |lvl2|
42
- lvl2.each_element do |field|
43
- if field.is_a? HeaderFieldNode then
44
- r[field.field_id.text_value] = field.field_value.text_value
45
- end
41
+ lvl1.each_element do |field|
42
+ if field.is_a? HeaderFieldNode then
43
+ r[field.field_id.text_value] = field.field_value.text_value
46
44
  end
47
45
  end
48
46
  end
@@ -58,14 +56,6 @@ module Gabc
58
56
 
59
57
  def create_music
60
58
  GabcMusic.new do |m|
61
-
62
- clef = elements.find {|e| e.respond_to? :clef_symbol }
63
- if clef != nil then
64
- m.clef = GabcClef.new(pitch: clef.clef_symbol.text_value.to_sym,
65
- line: clef.line_number.text_value.to_i,
66
- bemol: (clef.bemol.text_value == 'b'))
67
- end
68
-
69
59
  words = []
70
60
  each_element do |ele|
71
61
  if ele.is_a? WordNode then
@@ -115,6 +105,12 @@ module Gabc
115
105
  arr << GabcDivisio.new do |d|
116
106
  d.type = ele.text_value
117
107
  end
108
+ elsif ele.is_a? ClefNode then
109
+ arr << GabcClef.new do |c|
110
+ c.pitch = ele.clef_symbol.text_value.to_sym
111
+ c.bemol = ele.bemol.text_value == 'b'
112
+ c.line = ele.line_number.text_value.to_i
113
+ end
118
114
  else
119
115
  collect_notes ele, arr
120
116
  end
@@ -125,14 +121,14 @@ module Gabc
125
121
  end
126
122
 
127
123
  module SyllableNode
128
-
129
124
  end
130
125
 
131
126
  class NoteNode < SyntaxNode
132
-
133
127
  end
134
128
 
135
129
  module DivisioNode
130
+ end
136
131
 
132
+ module ClefNode
137
133
  end
138
134
  end
@@ -18,7 +18,8 @@ class LilypondConvertor
18
18
  ':' => '\bar "|"',
19
19
  ';' => '\bar "|"',
20
20
  '::' => '\bar "||"',
21
- ',' => '\bar "\'"'
21
+ ',' => '\bar "\'"',
22
+ '`' => '\breathe \bar ""'
22
23
  }
23
24
 
24
25
  def initialize(settings={})
@@ -34,20 +35,23 @@ class LilypondConvertor
34
35
  # converts GabcScore to Lilypond source
35
36
  def convert(score)
36
37
  header = score.header.keys.sort.collect do |k|
37
- " #{k} = \"#{score.header[k]}\""
38
+ " #{k} = \"#{score.header[k]}\""
38
39
  end.join "\n"
39
40
 
40
41
  notes = []
41
42
  lyrics = []
42
43
 
43
- clef = score.music.clef
44
- if clef == nil then
45
- clef = DEFAULT_CLEF
46
- end
44
+ clef = DEFAULT_CLEF
47
45
  @gabc_reader = GabcPitchReader.new clef.pitch, clef.line
48
46
 
49
- score.music.words.each do |word|
50
- notes << word_notes(word, clef)
47
+ score.music.words.each_with_index do |word,i|
48
+ current = word_notes(word, clef)
49
+ if @settings[:cadenza] &&
50
+ ! (notes.empty? || current.empty? ||
51
+ notes.last.include?('\bar') || current.include?('\bar'))
52
+ notes << '\bar ""'
53
+ end
54
+ notes << current unless current.empty?
51
55
  lyrics << word_lyrics(word)
52
56
  end
53
57
 
@@ -78,7 +82,7 @@ class LilypondConvertor
78
82
  if @settings[:header] and
79
83
  (header.size > 0 or @settings[:header] == 'always') then
80
84
  r += " \\header {\n" +
81
- " #{header}\n" +
85
+ "#{header}\n" +
82
86
  " }\n"
83
87
  end
84
88
 
@@ -108,17 +112,21 @@ class LilypondConvertor
108
112
  if notes.empty? then
109
113
  r << 's'
110
114
  else
111
- sylnotes = notes.collect do |n|
115
+ sylnotes = []
116
+ notes.each do |n|
112
117
  if n.is_a? GabcNote then
113
- NoteFactory.lily_abs_pitch(@gabc_reader.pitch(n.pitch))
114
-
118
+ pitch = @gabc_reader.pitch(n.pitch)
119
+ sylnotes << NoteFactory.lily_abs_pitch(pitch)
115
120
  elsif n.is_a? GabcDivisio then
116
121
  divisio = n.type
117
122
  unless BARS.has_key? divisio
118
123
  raise RuntimeError.new "Unhandled bar type '#{n.type}'"
119
124
  end
120
125
 
121
- BARS[divisio].dup
126
+ sylnotes << BARS[divisio].dup
127
+
128
+ elsif n.is_a? GabcClef then
129
+ @gabc_reader = GabcPitchReader.new n.pitch, n.line
122
130
 
123
131
  else
124
132
  raise RuntimeError.new "Unknown music content #{n}"
@@ -1,4 +1,4 @@
1
- # encoding: UTF-8
1
+ # encoding: utf-8
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -7,7 +7,7 @@ describe GabcParser do
7
7
  before :each do
8
8
  # beginning of the Populus Sion example
9
9
  @src = "name: Populus Sion;\n%%\n
10
- (c3) Pó(eh/hi)pu(h)lus(h) Si(hi)on,(hgh.) *(;)
10
+ (c3) Pó(eh/hi)pu(h)lus(h) Si(hi)on,(hgh.) *(;)
11
11
  ec(hihi)ce(e.) Dó(e.f!gwh/hi)mi(h)nus(h) vé(hi)ni(ig/ih)et.(h.) (::)"
12
12
  @parser = GabcParser.new
13
13
  end
@@ -18,27 +18,141 @@ ec(hihi)ce(e.) Dó(e.f!gwh/hi)mi(h)nus(h) vé(hi)ni(ig/ih)et.(h.) (::)"
18
18
  end
19
19
  end
20
20
 
21
+ describe 'header' do
22
+ it 'two subsequent header fields' do
23
+ str = "name:Intret in conspectu;\noffice-part:Introitus;\n"
24
+ @parser.parse(str, root: :header).should be_truthy
25
+ end
26
+
27
+ it 'comment+header field' do
28
+ str = "%comment\nname:Intret in conspectu;\n"
29
+ @parser.parse(str, root: :header).should be_truthy
30
+ end
31
+
32
+ describe 'header field' do
33
+ def rparse(str)
34
+ @parser.parse(str, root: :header)
35
+ end
36
+
37
+ it 'accepts normal header field' do
38
+ rparse("name: Populus Sion;\n").should be_truthy
39
+ end
40
+
41
+ it 'accepts empty header field' do
42
+ rparse("name:;\n").should be_truthy
43
+ end
44
+
45
+ it 'accepts accentuated characters' do
46
+ rparse("name:Adorábo;\n").should be_truthy
47
+ end
48
+
49
+ it 'accepts value with semicolons' do
50
+ rparse("name: 1; 2; 3;\n").should be_truthy
51
+ end
52
+
53
+ it 'accepts multi-line value' do
54
+ rparse("name: 1\n2;;\n").should be_truthy
55
+ end
56
+ end
57
+ end
58
+
21
59
  describe 'lyrics_syllable rule' do
22
- it 'does not accept space' do
23
- @parser.parse(' ', root: :lyrics_syllable).should be_nil
60
+ def rparse(str)
61
+ @parser.parse(str, root: :lyrics_syllable)
62
+ end
63
+
64
+ it 'does not accept space alone' do
65
+ rparse(' ').should be nil
66
+ end
67
+
68
+ it 'may end with space' do
69
+ rparse('hi ').should be_truthy
70
+ end
71
+
72
+ it 'may contain space' do
73
+ rparse('hi :').should be_truthy
74
+ end
75
+
76
+ it 'may contain several spaces' do
77
+ rparse('hi :').should be_truthy
78
+ end
79
+
80
+ it 'may contain several space-separated chunks' do
81
+ rparse('hi hey :').should be_truthy
24
82
  end
25
83
 
26
84
  it 'does not accept string beginning with space' do
27
- @parser.parse(' aa', root: :lyrics_syllable).should be_nil
85
+ rparse(' aa').should be nil
28
86
  end
29
87
 
30
88
  it 'accepts ascii characters' do
31
- @parser.parse('aa', root: :lyrics_syllable).should be_true
89
+ rparse('aa').should be_truthy
32
90
  end
33
91
 
34
92
  it 'accepts characters with accents' do
35
- @parser.parse('áéíóúý', root: :lyrics_syllable).should be_true
93
+ rparse('áéíóúý').should be_truthy
94
+ end
95
+
96
+ it 'accepts numbers' do
97
+ rparse('12').should be_truthy
36
98
  end
37
99
  end
38
100
 
39
101
  describe 'regular_word_character rule' do
40
102
  it 'does not accept space' do
41
- @parser.parse(' ', root: :regular_word_character).should be_nil
103
+ @parser.parse(' ', root: :regular_word_character).should be nil
104
+ end
105
+ end
106
+
107
+ describe 'music' do
108
+ def rparse(str)
109
+ @parser.parse(str, root: :music)
110
+ end
111
+
112
+ it 'copes with divisions between notes' do
113
+ rparse('(a,b)').should be_truthy
114
+ end
115
+
116
+ it 'custos-division-clef' do
117
+ rparse('(z0::c3)').should be_truthy
118
+ end
119
+
120
+ it 'division-clef' do
121
+ rparse('(::c3)').should be_truthy
122
+ end
123
+
124
+ it 'custos-division' do
125
+ rparse('(z0::)').should be_truthy
126
+ end
127
+ end
128
+
129
+ describe 'comments in body' do
130
+ def rparse(str)
131
+ @parser.parse(str, root: :body)
132
+ end
133
+
134
+ it 'comment alone is ok' do
135
+ rparse('% hi').should be_truthy
136
+ end
137
+
138
+ it 'comment with trailing whitespace is ok' do
139
+ rparse('% hi ').should be_truthy
140
+ end
141
+
142
+ it 'comment after note is ok' do
143
+ rparse('(h) % hi').should be_truthy
144
+ end
145
+
146
+ it 'commented note is ok' do
147
+ rparse('%(h)').should be_truthy
148
+ end
149
+
150
+ it 'two subsequent comments are ok' do
151
+ rparse("%a\n%b").should be_truthy
152
+ end
153
+
154
+ it 'comment immediately after note' do
155
+ rparse("(a)%comment").should be_truthy
42
156
  end
43
157
  end
44
158
  end
@@ -13,12 +13,32 @@ describe GabcPitchReader do
13
13
  end
14
14
  end
15
15
 
16
- describe '#base returns absolute pitch of the lowest writable note (a)' do
17
- #it { GabcPitchReader.new(:c, 4).base.should eq NoteFactory["a"] }
18
- #it { GabcPitchReader.new(:f, 2).base.should eq NoteFactory["a"] }
16
+ describe '#base' do
17
+ describe 'returns absolute pitch of the lowest writable note (a)' do
18
+ it { GabcPitchReader.new(:c, 4).base.should eq NoteFactory["a"] }
19
+ it { GabcPitchReader.new(:f, 2).base.should eq NoteFactory["a"] }
19
20
 
20
- #it { GabcPitchReader.new(:c, 1).base.should eq NoteFactory["g'"] }
21
- #it { GabcPitchReader.new(:f, 1).base.should eq NoteFactory["c'"] }
21
+ it { GabcPitchReader.new(:c, 1).base.should eq NoteFactory["g'"] }
22
+ it { GabcPitchReader.new(:f, 1).base.should eq NoteFactory["c'"] }
23
+ end
24
+ end
25
+
26
+ describe '#pitch' do
27
+ describe 'in c4' do
28
+ before :each do
29
+ @pr = GabcPitchReader.new :c, 4
30
+ end
31
+ it { @pr.pitch('h').should eq NoteFactory["a'"] }
32
+ it { @pr.pitch('d').should eq NoteFactory["d'"] }
33
+ end
34
+
35
+ describe 'in f3' do
36
+ before :each do
37
+ @pr = GabcPitchReader.new :f, 3
38
+ end
39
+ it { @pr.pitch('h').should eq NoteFactory["f'"] }
40
+ it { @pr.pitch('d').should eq NoteFactory["b"] }
41
+ end
22
42
  end
23
43
  end
24
44
 
@@ -1,4 +1,4 @@
1
- # encoding: UTF-8
1
+ # encoding: utf-8
2
2
 
3
3
  require_relative 'spec_helper'
4
4
 
@@ -66,11 +66,6 @@ ec(hihi)ce(e.) Dó(e.f!gwh/hi)mi(h)nus(h) vé(hi)ni(ig/ih)et.(h.) (::)"
66
66
  @music = @parser.parse(@src).create_score.music
67
67
  end
68
68
 
69
- describe '#clef' do
70
- subject { @music.clef }
71
- it { should be_a GabcClef }
72
- end
73
-
74
69
  describe '#words' do
75
70
  subject { @music.words }
76
71
  it { should be_a Array }
@@ -79,37 +74,6 @@ ec(hihi)ce(e.) Dó(e.f!gwh/hi)mi(h)nus(h) vé(hi)ni(ig/ih)et.(h.) (::)"
79
74
  end
80
75
  end
81
76
 
82
- describe GabcClef do
83
-
84
- before :each do
85
- # beginning of the Populus Sion example
86
- @src = "name: Populus Sion;\n%%\n
87
- (c3) Pó(eh/hi)pu(h)lus(h) Si(hi)on,(hgh.) *(;)
88
- ec(hihi)ce(e.) Dó(e.f!gwh/hi)mi(h)nus(h) vé(hi)ni(ig/ih)et.(h.) (::)"
89
- @parser = GabcParser.new
90
- @music = @parser.parse(@src).create_score.music
91
- @clef = @music.clef
92
- end
93
-
94
- it 'should return key from the score' do
95
- @clef.to_s.should eq 'c3'
96
- end
97
-
98
- it 'has no bemol' do
99
- @clef.bemol.should be_false
100
- end
101
-
102
- describe 'has bemol' do
103
- before :each do
104
- src = "%%\n(cb3)"
105
- @music = @parser.parse(src).create_score.music
106
- end
107
-
108
- it { @music.clef.bemol.should be_true }
109
- it { @music.clef.to_s.should eq 'cb3' }
110
- end
111
- end
112
-
113
77
  describe GabcWord do
114
78
  before :each do
115
79
  # beginning of the Populus Sion example
@@ -118,7 +82,7 @@ describe GabcWord do
118
82
  ec(hihi)ce(e.) Dó(e.f!gwh/hi)mi(h)nus(h) vé(hi)ni(ig/ih)et.(h.) (::)"
119
83
  @parser = GabcParser.new
120
84
  @music = @parser.parse(@src).create_score.music
121
- @word = @music.words.first
85
+ @word = @music.words[1] # 0 is clef
122
86
  end
123
87
 
124
88
  describe 'a simple word' do
@@ -131,7 +95,7 @@ ec(hihi)ce(e.) Dó(e.f!gwh/hi)mi(h)nus(h) vé(hi)ni(ig/ih)et.(h.) (::)"
131
95
  it { @word.size.should eq 3 }
132
96
  it { @word.first.lyrics.should eq 'Pó' }
133
97
  it { @word[1].lyrics.should eq 'pu' }
134
- it { @music.words[1].first.lyrics.should eq 'Si' }
98
+ it { @music.words[2].first.lyrics.should eq 'Si' }
135
99
  it { @music.words[-2].last.lyrics.should eq 'et.' }
136
100
  it { @music.words.last.last.lyrics.should eq '' }
137
101
  end
@@ -80,6 +80,20 @@ describe LilypondConvertor do
80
80
  end
81
81
  end
82
82
 
83
+ describe 'inline clefs' do
84
+ it 'copes with two clefs after each other' do
85
+ gabc = gabc2score("%%\n(f3) (c1) (c2) (h)")
86
+ ly = "\\score { \\absolute { e'' } \\addlyrics { } }"
87
+ @c.convert_min(gabc).should eq ly
88
+ end
89
+
90
+ it 'correctly resolves pitch in different clefs' do
91
+ gabc = gabc2score("%%\n(f3) (c4) (h) (c2) (h)")
92
+ ly = "\\score { \\absolute { a' e'' } \\addlyrics { } }"
93
+ @c.convert_min(gabc).should eq ly
94
+ end
95
+ end
96
+
83
97
  describe 'barlines' do
84
98
 
85
99
  it 'translates : to \bar "|"' do
@@ -128,10 +142,28 @@ describe LilypondConvertor do
128
142
 
129
143
  describe 'optional features' do
130
144
 
131
- it 'cadenza' do
132
- LilypondConvertor.new(version: false, cadenza: true) \
133
- .convert_min(gabc2score("%%\n(c4) (j)\n")).should \
134
- eq '\score { \absolute { \cadenzaOn c\'\' } \addlyrics { } }'
145
+ describe 'cadenza' do
146
+ before :each do
147
+ @convertor = LilypondConvertor.new(version: false, cadenza: true)
148
+ end
149
+
150
+ it 'adds \cadenzaOn' do
151
+ gabc = gabc2score("%%\n(c4) (j)\n")
152
+ ly = '\score { \absolute { \cadenzaOn c\'\' } \addlyrics { } }'
153
+ @convertor.convert_min(gabc).should eq ly
154
+ end
155
+
156
+ it 'inserts invisible bar after each word' do
157
+ gabc = gabc2score("%%\n(c4) (j) (j)\n")
158
+ ly = '\score { \absolute { \cadenzaOn c\'\' \bar "" c\'\' } \addlyrics { } }'
159
+ @convertor.convert_min(gabc).should eq ly
160
+ end
161
+
162
+ it 'does not insert bars around a bar' do
163
+ gabc = gabc2score("%%\n(c4) (j) (:) (j)\n")
164
+ ly = '\score { \absolute { \cadenzaOn c\'\' \bar "|" c\'\' } \addlyrics { } }'
165
+ @convertor.convert_min(gabc).should eq ly
166
+ end
135
167
  end
136
168
 
137
169
  it 'lily version' do
data/spec/spec_helper.rb CHANGED
@@ -5,7 +5,6 @@
5
5
  #
6
6
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
7
  RSpec.configure do |config|
8
- config.treat_symbols_as_metadata_keys_with_true_values = true
9
8
  config.run_all_when_everything_filtered = true
10
9
  config.filter_run :focus
11
10
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lygre
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakub Pavlík
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-20 00:00:00.000000000 Z
11
+ date: 2016-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: treetop
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.4'
19
+ version: '1.6'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.4'
26
+ version: '1.6'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: polyglot
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '2.14'
61
+ version: '3.4'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '2.14'
68
+ version: '3.4'
69
69
  description: |
70
70
  two of the free music typesetting applications most popular
71
71
  among church musicians are LilyPond and Gregorio.
@@ -86,17 +86,18 @@ extra_rdoc_files: []
86
86
  files:
87
87
  - bin/grely.rb
88
88
  - lib/grely.rb
89
- - lib/lygre/lilypondconvertor.rb
90
- - lib/lygre/gabcsemantics.rb
89
+ - lib/lygre/gabcgrammar.treetop
91
90
  - lib/lygre/gabcpitchreader.rb
92
91
  - lib/lygre/gabcscore.rb
93
- - spec/gabcpitchreader_spec.rb
94
- - spec/spec_helper.rb
95
- - spec/gabcparser_spec.rb
92
+ - lib/lygre/gabcsemantics.rb
93
+ - lib/lygre/lilypondconvertor.rb
96
94
  - spec/gabcgrammar_spec.rb
95
+ - spec/gabcparser_spec.rb
96
+ - spec/gabcpitchreader_spec.rb
97
97
  - spec/gabcscore_spec.rb
98
98
  - spec/lilypondconvertor_spec.rb
99
99
  - spec/matchers.rb
100
+ - spec/spec_helper.rb
100
101
  homepage: http://github.com/igneus/lygre
101
102
  licenses:
102
103
  - LGPL-3.0
@@ -118,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
119
  version: '0'
119
120
  requirements: []
120
121
  rubyforge_project:
121
- rubygems_version: 2.1.11
122
+ rubygems_version: 2.4.8
122
123
  signing_key:
123
124
  specification_version: 4
124
125
  summary: converts music formats gabc -> lilypond