lygre 0.0.1 → 0.0.2

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