gly 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: 341817505f45deff8e6c9815061fa6cffa571858
4
- data.tar.gz: 64ff6cb093190e69c37ed874af5c9b34e1499c3f
3
+ metadata.gz: a1be7280dd39aa6117888f6779c409359202d8bb
4
+ data.tar.gz: b5bc60c05106a3472b4fa296cc0787f1c804ab8f
5
5
  SHA512:
6
- metadata.gz: 41ba343096d37f095b7e9ca1724a8692d7bf4ca6dfcac689e681e9c61c1c95067ec42ba18f6fa8de259f6bf70b1960e5108f1f2503be1044e8df64bb0ec6fa96
7
- data.tar.gz: a14a88215832854321ecadff5fd0f0c01a057d3ad991873aede7d91b879da35edfe197bca214144a55a4ad4ff893d0a365505849ce62020b9da7361a5fe9a2e8
6
+ metadata.gz: d695541f34baae56918b864e062387426889b55dbed9e1636688157c1b4eadec906556be053de0b4da8f3a588c1fe415a12104ae844a5045471bfd91dfcec32c
7
+ data.tar.gz: 8aab9514701279b9e4ab1f00282e323902924c5f9b38fcf2ab1aa2fd9e534759a8a62220a38fa72d08ec0711eb78fb78c499760b97ea901458bcf93c326d7415
data/lib/gly.rb CHANGED
@@ -1,5 +1,14 @@
1
1
  module Gly; end
2
2
 
3
- %w(parser gabc_convertor parsed_score headers lyrics document string_helpers).each do |mod|
3
+ %w(parser
4
+ gabc_convertor
5
+ parsed_score
6
+ headers
7
+ lyrics
8
+ document
9
+ document_gabc_convertor
10
+ preview_generator
11
+ lister
12
+ string_helpers).each do |mod|
4
13
  require "gly/#{mod}"
5
14
  end
@@ -5,90 +5,37 @@ module Gly
5
5
  class CLI < Thor
6
6
  desc 'gabc FILE ...', 'convert gly to gabc'
7
7
  def gabc(*files)
8
- files.each {|f| gabc_convert(parse(f)) }
8
+ files.each {|f| DocumentGabcConvertor.new(Parser.new.parse(f)).convert }
9
9
  end
10
10
 
11
11
  desc 'preview FILE ...', 'convert to gabc AND generate pdf preview'
12
12
  def preview(*files)
13
- files.each {|f| make_preview f }
13
+ files.each {|f| PreviewGenerator.new.process(Parser.new.parse(f)) }
14
14
  end
15
15
 
16
- private
17
-
18
- def parse(gly_file)
19
- document = File.open(gly_file) do |fr|
20
- Parser.new.parse(fr)
21
- end
22
- end
23
-
24
- def gabc_convert(doc)
25
- doc.scores.each_with_index do |score, si|
26
- score_id = score.headers['id'] || si.to_s
27
- out_fname = File.basename(doc.path)
28
- .sub(/\.gly\Z/i, "_#{score_id}.gabc")
29
- File.open(out_fname, 'w') do |fw|
30
- GabcConvertor.new.convert score, fw
31
- end
32
- yield score, out_fname if block_given?
16
+ desc 'list FILE ...', 'list scores contained in files'
17
+ option :recursive, type: :boolean, aliases: :r, banner: 'recursively traverse directories', default: false
18
+ def list(*files)
19
+ if files.empty?
20
+ STDERR.puts 'No file specified.'
21
+ exit 1
33
22
  end
34
- end
35
-
36
- def make_preview(gly_file)
37
- doc = parse(gly_file)
38
-
39
- tex_header = <<EOS
40
- % LuaLaTeX
41
-
42
- \\documentclass[a4paper, 12pt]{article}
43
- \\usepackage[latin]{babel}
44
- \\usepackage[left=2cm, right=2cm, top=2cm, bottom=2cm]{geometry}
45
-
46
- \\usepackage{fontspec}
47
23
 
48
- % for gregorio
49
- \\usepackage{luatextra}
50
- \\usepackage{graphicx}
51
- \\usepackage{gregoriotex}
52
-
53
- \\title{#{doc.header['title']}}
54
-
55
- \\begin{document}
56
-
57
- #{doc.header['title'] && '\\maketitle'}
58
-
59
- EOS
60
-
61
- tex_fname = File.basename(gly_file).sub(/\.gly\Z/i, '.tex')
62
- File.open(tex_fname, 'w') do |fw|
63
- fw.puts tex_header
64
-
65
- gabc_convert(doc) do |score, gabc_fname|
66
- system "gregorio #{gabc_fname}"
67
- gtex_fname = gabc_fname.sub /\.gabc/i, ''
68
- piece_title = %w(book manuscript arranger author).collect do |m|
69
- score.headers[m]
70
- end.delete_if(&:nil?).join ', '
71
- fw.puts "\\commentary{\\footnotesize{#{piece_title}}}\n" unless piece_title.empty?
72
-
73
- annotations = score.headers.each_value('annotation')
74
- begin
75
- fw.puts "\\setfirstannotation{#{annotations.next}}"
76
- fw.puts "\\setsecondannotation{#{annotations.next}}"
77
- rescue StopIteration
78
- # ok, no more annotations
24
+ if options[:recursive]
25
+ files = files.collect do |f|
26
+ if File.directory?(f)
27
+ Dir[File.join(f, '**/*.gly')]
28
+ else
29
+ f
79
30
  end
80
-
81
- fw.puts "\\includescore{#{gtex_fname}}\n\\vspace{1cm}"
82
31
  end
83
-
84
- # tagline
85
- fw.puts "\n\\vfill\n\\begin{center}"
86
- fw.puts "\\texttt{gly preview https://github.com/igneus/gly}"
87
- fw.puts "\\end{center}\n"
88
- fw.puts "\n\\end{document}"
32
+ files.flatten!
89
33
  end
90
34
 
91
- system "lualatex #{tex_fname}"
35
+ lister = Lister.new(files)
36
+ lister.list(STDOUT, STDERR)
37
+
38
+ exit(lister.error? ? 1 : 0)
92
39
  end
93
40
  end
94
41
  end
@@ -0,0 +1,34 @@
1
+ module Gly
2
+ class DocumentGabcConvertor
3
+ def initialize(document)
4
+ @doc = document
5
+ end
6
+
7
+ def convert
8
+ each_score_with_gabcname do |score, out_fname|
9
+ File.open(out_fname, 'w') do |fw|
10
+ GabcConvertor.new.convert score, fw
11
+ end
12
+ yield score, out_fname if block_given?
13
+ end
14
+ end
15
+
16
+ # iterates over document scores,
17
+ # yields score and filename of it's generated gabc file
18
+ def each_score_with_gabcname
19
+ @doc.scores.each_with_index do |score, si|
20
+ yield score, output_fname(score, si)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def output_fname(score, score_index=nil)
27
+ score_id = score.headers['id'] || score_index.to_s
28
+ score_id = '_' + score_id unless score_id.empty?
29
+
30
+ File.basename(@doc.path)
31
+ .sub(/\.gly\Z/i, "#{score_id}.gabc")
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,23 @@
1
+ module Gly
2
+ class DocumentGabcConvertor
3
+ def initialize(document)
4
+ @doc = document
5
+ end
6
+
7
+ def convert
8
+ @doc.scores.each_with_index do |score, si|
9
+ score_id = score.headers['id'] || si.to_s
10
+ out_fname = File.basename(doc.path)
11
+ .sub(/\.gly\Z/i, "_#{score_id}.gabc")
12
+ File.open(out_fname, 'w') do |fw|
13
+ GabcConvertor.new.convert score, fw
14
+ end
15
+ yield score, out_fname if block_given?
16
+ end
17
+ end
18
+
19
+ def output_fname(input_fname, score_id=nil)
20
+
21
+ end
22
+ end
23
+ end
@@ -1,5 +1,7 @@
1
+ require 'stringio'
2
+
1
3
  module Gly
2
- # converts parsed gly to gabc
4
+ # takes ParsedScore, translates it to gabc
3
5
  class GabcConvertor
4
6
  def convert(score, out=StringIO.new)
5
7
  score.headers.each_pair do |key,value|
@@ -41,7 +43,7 @@ module Gly
41
43
  end
42
44
 
43
45
  def differentia?(chunk)
44
- chunk =~ /\A*[,;:]+\Z/ # differentia
46
+ chunk =~ /\A*[,;:`]+\Z/ # differentia
45
47
  end
46
48
 
47
49
  # is the given music chunk capable of bearing lyrics?
@@ -0,0 +1,32 @@
1
+ module Gly
2
+ class Lister
3
+ def initialize(files)
4
+ @files = files
5
+ @error = false
6
+ end
7
+
8
+ def list(io, errio)
9
+ @files.each do |f|
10
+ begin
11
+ document = Parser.new.parse(f)
12
+ rescue SystemCallError => err # Errno::WHATEVER
13
+ errio.puts "Cannot read file '#{f}': #{err.message}"
14
+ @error = true
15
+ next
16
+ end
17
+
18
+ io.puts
19
+ io.puts "== #{f}"
20
+
21
+ document.scores.each do |s|
22
+ l = s.lyrics.readable
23
+ io.puts l unless l.empty?
24
+ end
25
+ end
26
+ end
27
+
28
+ def error?
29
+ @error
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ module Gly
2
+ class Lister
3
+ def initialize(files)
4
+ @files = files
5
+ end
6
+
7
+ def list(io, errio)
8
+ was_error = false
9
+
10
+ files.each do |f|
11
+ begin
12
+ document = parse(f)
13
+ rescue SystemCallError => err # Errno::WHATEVER
14
+ errio.puts "Cannot read file '#{f}': #{err.message}"
15
+ was_error = true
16
+ next
17
+ end
18
+
19
+ puts
20
+ puts "== #{f}"
21
+
22
+ document.scores.each do |s|
23
+ l = s.lyrics.readable
24
+ puts l unless l.empty?
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -23,7 +23,11 @@ module Gly
23
23
  end
24
24
 
25
25
  def_delegator :@words, :each, :each_word
26
- def_delegators :@words, :empty?, :<<
26
+ def_delegators :@words, :<<, :empty?
27
+
28
+ def readable
29
+ @words.collect(&:readable).join ' '
30
+ end
27
31
  end
28
32
 
29
33
  class Word
@@ -35,5 +39,12 @@ module Gly
35
39
 
36
40
  def_delegators :@syllables, :<<, :push
37
41
  def_delegator :@syllables, :each, :each_syllable
42
+
43
+ def readable
44
+ without_directives = @syllables.collect do |s|
45
+ s.start_with?('!') ? s[1..-1] : s
46
+ end
47
+ without_directives.join
48
+ end
38
49
  end
39
50
  end
@@ -1,9 +1,37 @@
1
+ require 'stringio'
2
+
1
3
  module Gly
2
4
  # parses gly source
3
5
  class Parser
4
- SYLLABLE_SEP = '--'
6
+ def initialize(syllable_separator='--')
7
+ @syllable_separator = syllable_separator
8
+ end
9
+
10
+ def parse(source)
11
+ if source.is_a? String
12
+ if File.file? source
13
+ parse_fname source
14
+ elsif source == '-'
15
+ parse_io STDIN
16
+ else
17
+ parse_str source
18
+ end
19
+ else
20
+ parse_io source
21
+ end
22
+ end
23
+
24
+ def parse_fname(str)
25
+ File.open(str) do |fr|
26
+ parse_io fr
27
+ end
28
+ end
29
+
30
+ def parse_str(str)
31
+ parse_io(StringIO.new(source))
32
+ end
5
33
 
6
- def parse(io)
34
+ def parse_io(io)
7
35
  @doc = Document.new
8
36
  @score = ParsedScore.new
9
37
 
@@ -61,7 +89,7 @@ module Gly
61
89
  EXPLICIT_LYRICS_RE = /\A\\l(yrics)?\s+/
62
90
 
63
91
  def lyrics_line?(str)
64
- str =~ EXPLICIT_LYRICS_RE || str.include?(SYLLABLE_SEP) || contains_unmusical_letters?(str)
92
+ str =~ EXPLICIT_LYRICS_RE || str.include?(@syllable_separator) || contains_unmusical_letters?(str)
65
93
  end
66
94
 
67
95
  def in_header_block?
@@ -83,16 +111,15 @@ module Gly
83
111
  # separator
84
112
  str
85
113
  .sub(EXPLICIT_LYRICS_RE, '')
86
- .split(/(?<!#{SYLLABLE_SEP})\s+(?!#{SYLLABLE_SEP})/)
114
+ .split(/(?<!#{@syllable_separator})\s+(?!#{@syllable_separator})/)
87
115
  .each do |word|
88
- @score.lyrics << Word.new(word.split(/\s*#{SYLLABLE_SEP}\s*/))
116
+ @score.lyrics << Word.new(word.split(/\s*#{@syllable_separator}\s*/))
89
117
  end
90
118
  end
91
119
 
92
120
  def parse_music(str)
93
121
  # music chunks: split by whitespace out of brackets
94
- str.split(/\s+/).each do |chunk|
95
- chunk.sub!(/\A\((.*?)\)\Z/, '\1') # unparenthesize
122
+ StringHelpers.music_split(str).each do |chunk|
96
123
  @score.music << chunk
97
124
  end
98
125
  end
@@ -0,0 +1,48 @@
1
+ require 'stringio'
2
+
3
+ module Gly
4
+ # Takes Gly::Document, builds a pdf preview
5
+ # (or at least generates all necessary assets)
6
+ class PreviewGenerator
7
+ def process(document)
8
+ tpl_name = File.join(File.dirname(__FILE__), 'templates/lualatex_document.tex')
9
+ template = File.read(tpl_name)
10
+
11
+ doc_body = fw = StringIO.new
12
+
13
+ convertor = DocumentGabcConvertor.new(document)
14
+ convertor.each_score_with_gabcname do |score, gabc_fname|
15
+ system "gregorio #{gabc_fname}"
16
+ gtex_fname = gabc_fname.sub /\.gabc/i, ''
17
+ piece_title = %w(book manuscript arranger author).collect do |m|
18
+ score.headers[m]
19
+ end.delete_if(&:nil?).join ', '
20
+ fw.puts "\\commentary{\\footnotesize{#{piece_title}}}\n" unless piece_title.empty?
21
+
22
+ annotations = score.headers.each_value('annotation')
23
+ begin
24
+ fw.puts "\\setfirstannotation{#{annotations.next}}"
25
+ fw.puts "\\setsecondannotation{#{annotations.next}}"
26
+ rescue StopIteration
27
+ # ok, no more annotations
28
+ end
29
+
30
+ fw.puts "\\includescore{#{gtex_fname}}\n\\vspace{1cm}"
31
+ end
32
+
33
+ replacements = {
34
+ title: document.header['title'],
35
+ maketitle: (document.header['title'] && '\maketitle'),
36
+ body: doc_body.string
37
+ }
38
+ tex = template % replacements
39
+
40
+ out_fname = File.basename(document.path).sub(/\.gly\Z/i, '.tex')
41
+ File.open(out_fname, 'w') do |fw|
42
+ fw.puts tex
43
+ end
44
+
45
+ system "lualatex #{out_fname}"
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,7 @@
1
+ module Gly
2
+ # Takes Gly::Document, builds a pdf preview
3
+ # (or at least generates all necessary assets)
4
+ class PreviewGenerator
5
+
6
+ end
7
+ end
@@ -1,7 +1,7 @@
1
1
  module Gly
2
2
  module StringHelpers
3
3
  extend self
4
-
4
+
5
5
  # splits string by whitespace that is not enclosed
6
6
  # in brackets.
7
7
  # At the same time removes brackets.
@@ -12,10 +12,16 @@ module Gly
12
12
  in_brackets = false
13
13
  str.chars.each_with_index do |char, chi|
14
14
  if in_brackets
15
- next if char != ')'
16
-
15
+ if char == ')'
16
+ in_brackets = false
17
+ chunks << str[chunk_start .. chi-1]
18
+ chunk_start = chi + 1
19
+ end
17
20
  else
18
- if char =~ /^\s$/
21
+ if char == '('
22
+ in_brackets = true
23
+ chunk_start = chi + 1
24
+ elsif char =~ /^\s$/
19
25
  if chunk_start != chi
20
26
  chunks << str[chunk_start .. chi-1]
21
27
  end
@@ -24,7 +30,9 @@ module Gly
24
30
  end
25
31
  end
26
32
 
27
- chunks << str[chunk_start .. -1]
33
+ if chunk_start < str.size
34
+ chunks << str[chunk_start .. -1]
35
+ end
28
36
 
29
37
  chunks
30
38
  end
@@ -24,9 +24,7 @@ module Gly
24
24
  end
25
25
  end
26
26
 
27
- if chunk_start != chi
28
- chunks << str[chunk_start .. chi-1]
29
- end
27
+ chunks << str[chunk_start .. -1]
30
28
 
31
29
  chunks
32
30
  end
@@ -0,0 +1,27 @@
1
+ %% LuaLaTeX
2
+
3
+ \documentclass[a4paper, 12pt]{article}
4
+ \usepackage[latin]{babel}
5
+ \usepackage[left=2cm, right=2cm, top=2cm, bottom=2cm]{geometry}
6
+
7
+ \usepackage{fontspec}
8
+
9
+ %% for gregorio
10
+ \usepackage{luatextra}
11
+ \usepackage{graphicx}
12
+ \usepackage{gregoriotex}
13
+
14
+ \title{%{title}}
15
+
16
+ \begin{document}
17
+
18
+ %{maketitle}
19
+
20
+ %{body}
21
+
22
+ %% tagline
23
+ \vfill
24
+ \begin{center}
25
+ \texttt{gly preview https://github.com/igneus/gly}
26
+ \end{center}
27
+ \end{document}
@@ -0,0 +1,27 @@
1
+ % LuaLaTeX
2
+
3
+ \documentclass[a4paper, 12pt]{article}
4
+ \usepackage[latin]{babel}
5
+ \usepackage[left=2cm, right=2cm, top=2cm, bottom=2cm]{geometry}
6
+
7
+ \usepackage{fontspec}
8
+
9
+ % for gregorio
10
+ \usepackage{luatextra}
11
+ \usepackage{graphicx}
12
+ \usepackage{gregoriotex}
13
+
14
+ \title{#{doc.header['title']}}
15
+
16
+ \begin{document}
17
+
18
+ %{maketitle}
19
+
20
+ %{body}
21
+
22
+ % tagline
23
+ \vfill
24
+ \begin{center}
25
+ \texttt{gly preview https://github.com/igneus/gly}
26
+ \end{center}
27
+ \end{document}
@@ -8,8 +8,9 @@ class StringHelpersTest < GlyTest
8
8
  ['simple_whitespace', 'aa aa', ['aa', 'aa']],
9
9
  ['leading_trailing_whitespace', ' a a ', ['a', 'a']],
10
10
  ['bracketted', '(a)', ['a']],
11
+ ['empty', '()', ['']]
11
12
  ]
12
-
13
+
13
14
  examples.each do |e|
14
15
  name, given, expected = e
15
16
  define_method "test_#{name}" do
@@ -2,8 +2,18 @@ require_relative 'test_helper'
2
2
 
3
3
  class StringHelpersTest < GlyTest
4
4
  SH = Gly::StringHelpers
5
+
6
+ examples = [
7
+ ['single_chunk', 'a', ['a']],
8
+ ['simple_whitespace', 'aa aa', ['aa', 'aa']],
9
+ ['leading_trailing_whitespace', ' a a ', ['a', 'a']],
10
+ ['bracketted', '(a)', ['a']],
11
+ ]
5
12
 
6
- def test_simple_whitespace_split
7
- assert_equal ['aa', 'aa'], SH.music_split('aa aa')
13
+ examples.each do |e|
14
+ name, given, expected = e
15
+ define_method "test_#{name}" do
16
+ assert_equal expected, SH.music_split(given)
17
+ end
8
18
  end
9
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gly
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: 2015-12-15 00:00:00.000000000 Z
11
+ date: 2015-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -49,23 +49,26 @@ description: "# gly\n\nWriter-friendly Gregorian notation format compiling to ga
49
49
  or\n lyrics alone is possible (useful for a composer)\n * syllabified lyrics
50
50
  entered in a format inspired by LilyPond\n* music and lyrics can be interspersed
51
51
  as needed\n* no semicolons in the header\n* custom header fields supported (commented
52
- out in the GABC output;\n as gregorio crashes on headers it doesn't know)\n* several
53
- scores per file (when compiled to gabc, each becomes\n a separate file)\n* compile
54
- pdf preview by a single command, without writing any (La)TeX\n\n## Examples\n\nTypical
55
- GABC source of an antiphon looks like this:\n\n name: Nativitas gloriosae;\n
56
- \ office-part: laudes, 1. ant.;\n occasion: In Nativitate B. Mariae Virginis;\n
57
- \ book: Antiphonale Romanum 1912, pg. 704;\n mode: 8;\n initial-style: 1;\n
58
- \ %%\n \n (c4) NA(g)TI(g)VI(g)TAS(gd) glo(f)ri(gh)ó(g)sae(g) * (,)\n Vír(g)gi(g)nis(hi)
59
- Ma(gh)rí(gf)ae,(f) (;)\n ex(f) (g)mi(h)ne(h) A(hiwji)bra(hg)hae,(g) (;)\n or(gh~)tae(g)
60
- de(g) tri(g)bu(fe/fgf) Ju(d)da,(d) (;)\n cla(df!gh)ra(g) ex(f) stir(hg~)pe(hi)
61
- Da(h)vid.(g) (::)\n\nCorresponding GLY may look like this:\n\n name: Nativitas
62
- gloriosae\n office-part: laudes, 1. ant.\n occasion: In Nativitate B. Mariae
63
- Virginis\n book: Antiphonale Romanum 1912, pg. 704\n mode: 8\n initial-style:
64
- 1\n \n c4 g g g gd f gh g g ,\n g g hi gh gf f ;\n f g h h hiwji hg
65
- g ;\n gh~ g g g fe/fgf d d ;\n df!gh g f hg~ hi h g ::\n \n NA -- TI
66
- -- VI -- TAS glo -- ri -- ósae *\n Vír -- gi -- nis Ma -- rí -- ae,\n ex sé
67
- -- mi -- ne A -- bra -- hae,\n or -- tae de tri -- bu Ju -- da,\n cla -- ra
68
- ex stir -- pe Da -- vid.\n\nOr, with music and lyrics interlaced:\n\n name: Nativitas
52
+ out in the GABC output,\n as gregorio doesn't tolerate headers it doesn't know)\n*
53
+ several scores per file (when compiled to gabc, each becomes\n a separate file)\n*
54
+ compile pdf preview by a single command, without writing any (La)TeX\n\n## Real
55
+ world examples\n\n* [Proper Divine Office chants of Bohemian Premonstratensian houses][opraem_boh]\n\n##
56
+ Basic examples\n\nTypical GABC source of an antiphon looks like this:\n\n name:
57
+ Nativitas gloriosae;\n office-part: laudes, 1. ant.;\n occasion: In Nativitate
58
+ B. Mariae Virginis;\n book: Antiphonale Romanum 1912, pg. 704;\n mode: 8;\n
59
+ \ initial-style: 1;\n %%\n \n (c4) NA(g)TI(g)VI(g)TAS(gd) glo(f)ri(gh)ó(g)sae(g)
60
+ * (,)\n Vír(g)gi(g)nis(hi) Ma(gh)rí(gf)ae,(f) (;)\n ex(f)(g)mi(h)ne(h)
61
+ A(hiwji)bra(hg)hae,(g) (;)\n or(gh~)tae(g) de(g) tri(g)bu(fe/fgf) Ju(d)da,(d)
62
+ (;)\n cla(df!gh)ra(g) ex(f) stir(hg~)pe(hi) Da(h)vid.(g) (::)\n\nCorresponding
63
+ GLY may look like this:\n\n name: Nativitas gloriosae\n office-part: laudes,
64
+ 1. ant.\n occasion: In Nativitate B. Mariae Virginis\n book: Antiphonale Romanum
65
+ 1912, pg. 704\n mode: 8\n initial-style: 1\n \n c4 g g g gd f gh g g
66
+ ,\n g g hi gh gf f ;\n f g h h hiwji hg g ;\n gh~ g g g fe/fgf d d ;\n
67
+ \ df!gh g f hg~ hi h g ::\n \n NA -- TI -- VI -- TAS glo -- ri -- ósae *\n
68
+ \ Vír -- gi -- nis Ma -- rí -- ae,\n ex -- mi -- ne A -- bra -- hae,\n or
69
+ -- tae de tri -- bu Ju -- da,\n cla -- ra ex stir -- pe Da -- vid.\n\nOr, with
70
+ music and lyrics interlaced\n(this arrangement may be handy for larger scores,\nlike
71
+ full-notated hymns, sequences or nocturnal responsories):\n\n name: Nativitas
69
72
  gloriosae\n office-part: laudes, 1. ant.\n occasion: In Nativitate B. Mariae
70
73
  Virginis\n book: Antiphonale Romanum 1912, pg. 704\n mode: 8\n initial-style:
71
74
  1\n \n c4 g g g gd f gh g g ,\n NA -- TI -- VI -- TAS glo -- ri -- ósae
@@ -73,16 +76,70 @@ description: "# gly\n\nWriter-friendly Gregorian notation format compiling to ga
73
76
  g h h hiwji hg g ;\n ex sé -- mi -- ne A -- bra -- hae,\n \n gh~ g g g
74
77
  fe/fgf d d ;\n or -- tae de tri -- bu Ju -- da,\n \n df!gh g f hg~ hi h
75
78
  g ::\n cla -- ra ex stir -- pe Da -- vid.\n\nOther arrangements are also possible.
76
- Order of music and lyrics\nis actually ignored during processing.\n\n## Usage\n\nThis
77
- gem provides executable `gly`. Run `gly help` for full list\nof subcommands. The
78
- most important ones are:\n\n`gly gabc FILE1 ...`\n\nconverts given gly file(s) to
79
- one or more gabc files (one per score,\ni.e. one gly may spawn a bunch of gabcs).\n\n`gly
79
+ Order of music and lyrics\nis actually ignored during processing.\n\n## Installation\n\nInstall
80
+ Ruby (some 2.x version) runtime. Then install as any ruby gem:\n\n`gem install gly`\n\n##
81
+ Usage\n\nThis gem provides executable `gly`. Run `gly help` for full list\nof subcommands.
82
+ The most important ones are:\n\n`gly gabc FILE1 ...`\n\nconverts given gly file(s)
83
+ to one or more gabc files (one per score,\ni.e. one gly may spawn a bunch of gabcs).\n\n`gly
80
84
  preview FILE1 ...`\n\nAttempts to create a pdf document with all scores contained
81
- in each\ngly file. Expects gregorio and lualatex to be in PATH\nand gregoriotex
82
- to be installed and accessible by lualatex.\n\n## Tools\n\n[Emacs mode with syntax
85
+ in each\ngly file. Expects `gregorio` and `lualatex` to be in PATH\nand `gregoriotex`
86
+ to be installed and accessible by `lualatex`.\n\n## Tools\n\n[Emacs mode with syntax
83
87
  highlighting for gly][elisp]\n\n![Editing gly in emacs](/doc/img/gly_emacs_scr.png)\n\n##
84
- Run tests\n\nby executing `tests/run.rb`\n\n## License\n\nMIT\n\n[gregorio]: https://github.com/gregorio-project/gregorio\n[elisp]:
85
- /tree/master/elisp\n"
88
+ Syntax reference\n\nGly syntax is line-based.\nThe interpreter reads the input line
89
+ by line,\nand depending on context it interprets each line as\ne.g. music, lyrics
90
+ or header field.\n\nThe syntax is quite permissive, not requiring a lot of delimiters\nor
91
+ hints for the parser concerning what each line means.\nMostly the parser guesses
92
+ the meaning correctly.\nWhere not, meaning of each line can be stated explicitly.\n\n###
93
+ 1. Comments\n\nWhen a `%` sign is encountered, everything until the end of line\nis
94
+ considered a comment and not interpreted.\n(Comment syntax is the same as in gabc.)\n\nPlease
95
+ note, that when compiling to gabc, comments are dropped\nand don't appear in the
96
+ resulting gabc file.\n\n### 2. Whitespace\n\nEmpty lines are ignored.\n\n### 3.
97
+ Scores\n\nA new score begins at the beginning of a file or at a line containing\na
98
+ single keyword '\\score'.\n\nIt consists of\na header (optional, only permitted
99
+ at the beginning of a score)\nand music- and lyrics-lines.\nLines with music and
100
+ lyrics may appear in any order.\n\nScore ends with end of file or with explicit
101
+ beginning of a new score\nor another top-level element.\n\n#### 3.1 Score header\n\nScore
102
+ header consists of fields.\n\nEach header field is on it's own (one) line and consists
103
+ of\nidentifier, colon and value:\n\n`mode: 8`\n\nHeader field identifier may only
104
+ consist of alphanumeric characters,\nminus-sign and underscore. Value can contain
105
+ anything.\n\nScore header ends with first non-empty line identified by the parser\nas
106
+ music or lyrics.\n\nHeader field 'id' is special: if present, it is used as suffix\nof
107
+ the generated gabc file (instead of the default, which is\nnumeric position of the
108
+ score in the source document).\n\n#### 3.2 Lyrics\n\nSyntax of lyrics is inspired
109
+ by LilyPond.\nLyrics have to be manually syllabified. Default syllable delimiter\nis
110
+ double dash (minus) `--` with optional whitespace around.\n\n`cla -- ra ex stir
111
+ -- pe Da -- vid.`\n\nThe parser guesses meaning of the line by attempting to find\nsyllable
112
+ separator in it and by looking if it's alphanumeric\ncharacters contains something
113
+ that cannot be interpreted as music.\nIf any of these conditions is met, the line
114
+ is interpreted as lyrics.\n\nIf gly fails to guess your lyrics line correctly and
115
+ interprets\nit as music, place `\\lyrics` or short `\\l` at the beginning\nof the
116
+ unhappy line:\n\n`\\l a a a`\n\n#### 3.3 Music\n\nAny line appearing in a score
117
+ and not identified as header field\nor lyrics is music by default.\n\nMusic line
118
+ contains one or more music chunks separated by whitespace.\nFor music syntax see
119
+ [official gabc documentation][gabc] -\ngly doesn't change anything in this respect.\n\nMusic
120
+ chunks may be enclosed in parentheses as in gabc.\n(Of course you don't like the
121
+ parentheses and are happy that gly\nlet's you leave them out. But in some special
122
+ cases they come handy.)\n\n#### 3.4 Matching lyrics to music\n\nWhen processing
123
+ the gly source and producing gabc, music chunks\nare matched to lyric syllables.\n\nThere
124
+ are, however, a few special cases, to make it work conveniently:\n\nThese special
125
+ cases of music chunks don't get lyric syllable:\n\n* clef\n* music chunk containing
126
+ only a division - i.e. music chunk containing\n one of `,` , `;` , `:` , `::` alone\n\nException
127
+ to this rule are 'nonlyrical lyrics chunks'.\nCurrently there is only one built-in
128
+ nonlyrical lyric chunk:\nasterisk `*`.\nNormally it is treated as any other syllable,\nbut
129
+ if it meets a division, it is set as it's lyrics, while\na normal syllable wouldn't
130
+ be.\n\nIf you need to set some other syllable under a division,\nmake it 'nonlyrical'
131
+ by placing\nan exclamation mark at it's beginning, e.g. `!<i>Ps.</i>`\n\nIn the
132
+ other direction it is sometimes necessary to set a syllable\nnot matching any music
133
+ at all. In such cases empty music chunk\n`()` is what you need.\n\n### 4. Document
134
+ header\n\nEach gly document may optinally contain a document header.\nIt may appear
135
+ anywhere in the document, but best practice is to place\nit at the very beginning.\n\nDocument
136
+ header starts with keyword `\\header` and ends\nat the end of file or at the beginning
137
+ of another top-level element.\nThe syntax of it's content is the same\nas for [Score
138
+ header][].\n\nField 'title' in the document header is, if present,\nused by `gly
139
+ preview` as title of the generated pdf.\n\n## Run tests\n\nby executing `tests/run.rb`\n\n##
140
+ License\n\nMIT\n\n[gregorio]: https://github.com/gregorio-project/gregorio\n[gabc]:
141
+ http://gregorio-project.github.io/gabc/index.html\n[elisp]: /tree/master/elisp\n\n[opraem_boh]:
142
+ https://gist.github.com/igneus/1aed0b36e9b23b51526d\n"
86
143
  email: jkb.pavlik@gmail.com
87
144
  executables:
88
145
  - gly
@@ -97,18 +154,26 @@ files:
97
154
  - lib/gly/cli.rb~
98
155
  - lib/gly/document.rb
99
156
  - lib/gly/document.rb~
157
+ - lib/gly/document_gabc_convertor.rb
158
+ - lib/gly/document_gabc_convertor.rb~
100
159
  - lib/gly/gabc_convertor.rb
101
160
  - lib/gly/gabc_convertor.rb~
102
161
  - lib/gly/headers.rb
103
162
  - lib/gly/headers.rb~
163
+ - lib/gly/lister.rb
164
+ - lib/gly/lister.rb~
104
165
  - lib/gly/lyrics.rb
105
166
  - lib/gly/lyrics.rb~
106
167
  - lib/gly/parsed_score.rb
107
168
  - lib/gly/parsed_score.rb~
108
169
  - lib/gly/parser.rb
109
170
  - lib/gly/parser.rb~
171
+ - lib/gly/preview_generator.rb
172
+ - lib/gly/preview_generator.rb~
110
173
  - lib/gly/string_helpers.rb
111
174
  - lib/gly/string_helpers.rb~
175
+ - lib/gly/templates/lualatex_document.tex
176
+ - lib/gly/templates/lualatex_document.tex~
112
177
  - tests/examples.rb
113
178
  - tests/examples.rb~
114
179
  - tests/examples/gly/expected/block_lyrics.gabc