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 +4 -4
- data/bin/grely.rb +28 -26
- data/lib/lygre/gabcgrammar.treetop +239 -0
- data/lib/lygre/gabcscore.rb +0 -2
- data/lib/lygre/gabcsemantics.rb +11 -15
- data/lib/lygre/lilypondconvertor.rb +21 -13
- data/spec/gabcparser_spec.rb +122 -8
- data/spec/gabcpitchreader_spec.rb +25 -5
- data/spec/gabcscore_spec.rb +3 -39
- data/spec/lilypondconvertor_spec.rb +36 -4
- data/spec/spec_helper.rb +0 -1
- metadata +13 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c100850289adec3dc56f49db675050c9363706e0
|
4
|
+
data.tar.gz: a47121a23251de440329e1866dbacb532dd07152
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
#
|
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
data/lib/lygre/gabcscore.rb
CHANGED
data/lib/lygre/gabcsemantics.rb
CHANGED
@@ -38,11 +38,9 @@ module Gabc
|
|
38
38
|
r = {}
|
39
39
|
|
40
40
|
each_element do |lvl1|
|
41
|
-
lvl1.each_element do |
|
42
|
-
|
43
|
-
|
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
|
-
"
|
38
|
+
" #{k} = \"#{score.header[k]}\""
|
38
39
|
end.join "\n"
|
39
40
|
|
40
41
|
notes = []
|
41
42
|
lyrics = []
|
42
43
|
|
43
|
-
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.
|
50
|
-
|
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
|
-
"
|
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 =
|
115
|
+
sylnotes = []
|
116
|
+
notes.each do |n|
|
112
117
|
if n.is_a? GabcNote then
|
113
|
-
|
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}"
|
data/spec/gabcparser_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# encoding:
|
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
|
-
|
23
|
-
@parser.parse(
|
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
|
-
|
85
|
+
rparse(' aa').should be nil
|
28
86
|
end
|
29
87
|
|
30
88
|
it 'accepts ascii characters' do
|
31
|
-
|
89
|
+
rparse('aa').should be_truthy
|
32
90
|
end
|
33
91
|
|
34
92
|
it 'accepts characters with accents' do
|
35
|
-
|
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
|
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
|
17
|
-
|
18
|
-
|
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
|
-
|
21
|
-
|
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
|
|
data/spec/gabcscore_spec.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# encoding:
|
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
|
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[
|
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
|
-
|
132
|
-
|
133
|
-
.
|
134
|
-
|
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
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.
|
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:
|
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.
|
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.
|
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: '
|
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: '
|
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/
|
90
|
-
- lib/lygre/gabcsemantics.rb
|
89
|
+
- lib/lygre/gabcgrammar.treetop
|
91
90
|
- lib/lygre/gabcpitchreader.rb
|
92
91
|
- lib/lygre/gabcscore.rb
|
93
|
-
-
|
94
|
-
-
|
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.
|
122
|
+
rubygems_version: 2.4.8
|
122
123
|
signing_key:
|
123
124
|
specification_version: 4
|
124
125
|
summary: converts music formats gabc -> lilypond
|