jekyll-lilypond 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +99 -0
- data/LICENSE +21 -0
- data/README.md +98 -0
- data/files/rite.png +0 -0
- data/jekyll-lilypond.gemspec +23 -0
- data/lib/jekyll-lilypond/file_processor.rb +67 -0
- data/lib/jekyll-lilypond/lilypond_tag.rb +34 -0
- data/lib/jekyll-lilypond/tag.rb +17 -0
- data/lib/jekyll-lilypond/tag_processor.rb +56 -0
- data/lib/jekyll-lilypond/templates/basic.ly +45 -0
- data/lib/jekyll-lilypond/templates/empty.ly +1 -0
- data/lib/jekyll-lilypond/templates/figure.html +25 -0
- data/lib/jekyll-lilypond/templates/img.html +4 -0
- data/lib/jekyll-lilypond/templates/raw.html +1 -0
- data/lib/jekyll-lilypond/templates/raw.ly +1 -0
- data/lib/jekyll-lilypond/templates/showsource.html +36 -0
- data/lib/jekyll-lilypond/templates.rb +60 -0
- data/lib/jekyll-lilypond/version.rb +5 -0
- data/lib/jekyll-lilypond.rb +11 -0
- data/spec/file_processor_spec.rb +167 -0
- data/spec/fixtures/.gitignore +5 -0
- data/spec/fixtures/404.html +25 -0
- data/spec/fixtures/Gemfile +31 -0
- data/spec/fixtures/_config.yml +56 -0
- data/spec/fixtures/_layouts/basic_html.html +1 -0
- data/spec/fixtures/_layouts/vacuous_html.html +1 -0
- data/spec/fixtures/_layouts/vacuous_ly.ly +1 -0
- data/spec/fixtures/_layouts/variables_html.html +1 -0
- data/spec/fixtures/_layouts/variables_ly.ly +1 -0
- data/spec/fixtures/_posts/2021-01-16-welcome-to-jekyll.markdown +29 -0
- data/spec/fixtures/about.markdown +18 -0
- data/spec/fixtures/index.markdown +6 -0
- data/spec/fixtures/page.md +8 -0
- data/spec/integration_spec.rb +115 -0
- data/spec/spec_helper.rb +88 -0
- data/spec/tag_processor_spec.rb +135 -0
- data/spec/tag_spec.rb +51 -0
- data/spec/templates_spec.rb +175 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 03f518ed64fd17a4aa282f1e11c82f1ea127de1231919ad2f22f419f3a95d942
|
4
|
+
data.tar.gz: 8225e9fd20e2be85d2be52781a01d65de431313399d7313d754e416f78148c6c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 48f09dbd1c6101a2ff2d13500690f72efee15bfc7b33cc647ecf050de11f082de1bc195a16fa56d52958b7605c362cf7a21258498f0cce8c51015436261056c5
|
7
|
+
data.tar.gz: 0b51587b3ff6e62de63486833c9269bd961d025d047770431adcb8b7fb0c98207eb6798efee19ee6e175e7a705d4811216395004290f7fe223755552dac9788c
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.7.0)
|
5
|
+
public_suffix (>= 2.0.2, < 5.0)
|
6
|
+
colorator (1.1.0)
|
7
|
+
concurrent-ruby (1.1.7)
|
8
|
+
diff-lcs (1.4.4)
|
9
|
+
docile (1.3.5)
|
10
|
+
em-websocket (0.5.2)
|
11
|
+
eventmachine (>= 0.12.9)
|
12
|
+
http_parser.rb (~> 0.6.0)
|
13
|
+
eventmachine (1.2.7)
|
14
|
+
ffi (1.14.2)
|
15
|
+
forwardable-extended (2.6.0)
|
16
|
+
http_parser.rb (0.6.0)
|
17
|
+
i18n (1.8.7)
|
18
|
+
concurrent-ruby (~> 1.0)
|
19
|
+
jekyll (4.2.0)
|
20
|
+
addressable (~> 2.4)
|
21
|
+
colorator (~> 1.0)
|
22
|
+
em-websocket (~> 0.5)
|
23
|
+
i18n (~> 1.0)
|
24
|
+
jekyll-sass-converter (~> 2.0)
|
25
|
+
jekyll-watch (~> 2.0)
|
26
|
+
kramdown (~> 2.3)
|
27
|
+
kramdown-parser-gfm (~> 1.0)
|
28
|
+
liquid (~> 4.0)
|
29
|
+
mercenary (~> 0.4.0)
|
30
|
+
pathutil (~> 0.9)
|
31
|
+
rouge (~> 3.0)
|
32
|
+
safe_yaml (~> 1.0)
|
33
|
+
terminal-table (~> 2.0)
|
34
|
+
jekyll-feed (0.15.1)
|
35
|
+
jekyll (>= 3.7, < 5.0)
|
36
|
+
jekyll-sass-converter (2.1.0)
|
37
|
+
sassc (> 2.0.1, < 3.0)
|
38
|
+
jekyll-seo-tag (2.7.1)
|
39
|
+
jekyll (>= 3.8, < 5.0)
|
40
|
+
jekyll-watch (2.2.1)
|
41
|
+
listen (~> 3.0)
|
42
|
+
kramdown (2.3.0)
|
43
|
+
rexml
|
44
|
+
kramdown-parser-gfm (1.1.0)
|
45
|
+
kramdown (~> 2.0)
|
46
|
+
liquid (4.0.3)
|
47
|
+
listen (3.4.1)
|
48
|
+
rb-fsevent (~> 0.10, >= 0.10.3)
|
49
|
+
rb-inotify (~> 0.9, >= 0.9.10)
|
50
|
+
mercenary (0.4.0)
|
51
|
+
minima (2.5.1)
|
52
|
+
jekyll (>= 3.5, < 5.0)
|
53
|
+
jekyll-feed (~> 0.9)
|
54
|
+
jekyll-seo-tag (~> 2.1)
|
55
|
+
pathutil (0.16.2)
|
56
|
+
forwardable-extended (~> 2.6)
|
57
|
+
public_suffix (4.0.6)
|
58
|
+
rb-fsevent (0.10.4)
|
59
|
+
rb-inotify (0.10.1)
|
60
|
+
ffi (~> 1.0)
|
61
|
+
rexml (3.2.4)
|
62
|
+
rouge (3.26.0)
|
63
|
+
rspec (3.10.0)
|
64
|
+
rspec-core (~> 3.10.0)
|
65
|
+
rspec-expectations (~> 3.10.0)
|
66
|
+
rspec-mocks (~> 3.10.0)
|
67
|
+
rspec-core (3.10.1)
|
68
|
+
rspec-support (~> 3.10.0)
|
69
|
+
rspec-expectations (3.10.1)
|
70
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
71
|
+
rspec-support (~> 3.10.0)
|
72
|
+
rspec-mocks (3.10.1)
|
73
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
74
|
+
rspec-support (~> 3.10.0)
|
75
|
+
rspec-support (3.10.1)
|
76
|
+
safe_yaml (1.0.5)
|
77
|
+
sassc (2.4.0)
|
78
|
+
ffi (~> 1.9)
|
79
|
+
simplecov (0.21.2)
|
80
|
+
docile (~> 1.1)
|
81
|
+
simplecov-html (~> 0.11)
|
82
|
+
simplecov_json_formatter (~> 0.1)
|
83
|
+
simplecov-html (0.12.3)
|
84
|
+
simplecov_json_formatter (0.1.2)
|
85
|
+
terminal-table (2.0.0)
|
86
|
+
unicode-display_width (~> 1.1, >= 1.1.1)
|
87
|
+
unicode-display_width (1.7.0)
|
88
|
+
|
89
|
+
PLATFORMS
|
90
|
+
universal-darwin-19
|
91
|
+
|
92
|
+
DEPENDENCIES
|
93
|
+
jekyll
|
94
|
+
minima
|
95
|
+
rspec
|
96
|
+
simplecov
|
97
|
+
|
98
|
+
BUNDLED WITH
|
99
|
+
2.2.5
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2021 Leah Velleman
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# jekyll-lilypond
|
2
|
+
|
3
|
+
<p align="center">
|
4
|
+
<img src="files/rite.png" width="75%"/>
|
5
|
+
</p>
|
6
|
+
|
7
|
+
Automatically generate sheet music images by adding Lilypond blocks to your markdown files. Customize their
|
8
|
+
appearance using Liquid attributes. The plugin caches the images it generates, making auto-regeneration fast.
|
9
|
+
|
10
|
+
For complete documentation, see [the plugin website](https://www.velleman.org/jekyll-lilypond).
|
11
|
+
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
The plugin requires Lilypond and Inkscape. To use it in a Jekyll site,
|
16
|
+
add
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'jekyll-lilypond'
|
20
|
+
```
|
21
|
+
|
22
|
+
to your Gemfile and
|
23
|
+
|
24
|
+
```yaml
|
25
|
+
plugins:
|
26
|
+
- jekyll-lilypond
|
27
|
+
```
|
28
|
+
|
29
|
+
to your `_config.yml`.
|
30
|
+
|
31
|
+
## Quick start
|
32
|
+
|
33
|
+
Inside the block, write a Lilypond music expression.
|
34
|
+
```
|
35
|
+
{% lilypond alt: "Five notes of the A-minor scale" %}
|
36
|
+
a b c d e
|
37
|
+
{% endlilypond %}
|
38
|
+
```
|
39
|
+
The expression can include multiple staves, expressive marks, time and key signature changes, and any of the other notation Lilypond supports within a music
|
40
|
+
expression. For details, see [this brief summary](https://lilypond.org/doc/v2.20/Documentation/learning/score-is-a-_0028single_0029-compound-musical-expression) in the Lilypond teaching manual or [Wikipedia's list of common music expression details](https://en.wikipedia.org/wiki/Help:Score#Syntax).
|
41
|
+
|
42
|
+
To make customizations that can't be make within a music expression — for instance, to change the width or height of the score or specify a custom font —
|
43
|
+
use attributes on the `{% lilypond %}` tag. For more information on attributes, see [the plugin documentation](http://127.0.0.1:4000/jekyll-lilypond#attributes).
|
44
|
+
|
45
|
+
## Approach
|
46
|
+
|
47
|
+
### Caching
|
48
|
+
|
49
|
+
Lilypond runs more slowly than Jekyll, and regenerating every score would create a noticeable lag. This would be especially painful in auto-regenerate mode,
|
50
|
+
which is normally very responsive. To solve this, I cache images. Each Lilypond source file, and each resulting image, has a filename derived from the MD5 hash
|
51
|
+
of the source code. The plugin only compiles a Lilypond source file when the corresponding image does not yet exist.
|
52
|
+
|
53
|
+
To force the plugin to regenerate all of the score images for a site, which is sometimes useful for debugging, empty the `lilypond_files` directory.
|
54
|
+
|
55
|
+
To keep upload size to a minimum, you can also empty the `lilypond_files` directory and regenerate the site before deploying. This removes "stale" images
|
56
|
+
that are no longer in use.
|
57
|
+
|
58
|
+
### Templates
|
59
|
+
|
60
|
+
The plugin generates two kinds of code: Lilypond source files, which it uses to generate images, and HTML includes, which appear in the finished page
|
61
|
+
and contain the `img` element and surrounding markup.
|
62
|
+
|
63
|
+
To generate both kinds of source code, it uses Liquid templates. Liquid is the native templating language of Jekyll. Just as Jekyll users can write their own
|
64
|
+
templates to create new page layouts, users of this plugin can write their own templates to add simple features and customizations.
|
65
|
+
|
66
|
+
As well as allowing customization, using a template to generate Lilypond source avoids the need to repeat boilerplate. For instance, the default Lilypond
|
67
|
+
template begins like this:
|
68
|
+
```
|
69
|
+
\version "2.20.0"
|
70
|
+
\paper {
|
71
|
+
indent = 0\mm
|
72
|
+
short-indent = 0\mm
|
73
|
+
bottom-margin = 4\mm
|
74
|
+
oddHeaderMarkup = ##f
|
75
|
+
evenHeaderMarkup = ##f
|
76
|
+
oddFooterMarkup = ##f
|
77
|
+
evenFooterMarkup = ##f
|
78
|
+
...
|
79
|
+
}
|
80
|
+
```
|
81
|
+
These settings produce clean output without extraneous marks, headers, footers, or whitespace, but it would be a hassle to retype them in every Lilypond block.
|
82
|
+
Later parts of the template include correct code for setting the page width, font, and so on, which saves the user from needing to remember the somewhat
|
83
|
+
arbitrary syntax for doing those things.
|
84
|
+
|
85
|
+
### Future plans
|
86
|
+
|
87
|
+
The next thing on my agenda is to generate assets other than images. For instance, Lilypond can generate MIDI files and software synthesizers can generate
|
88
|
+
mp3 audio from MIDI. It would be nice to support those — and, beyond that, to support other workflows that users might think of. (Maybe someone will want to
|
89
|
+
generate video? Or do musical analysis on MIDI files?)
|
90
|
+
|
91
|
+
The most flexible way to do all this would be to let users specify workflow steps in a sitewide Rakefile, alongside whatever other deployment and
|
92
|
+
asset-processing tasks they may have specified there. Templates could then specify what sorts of generated files they require, and the plugin could call on
|
93
|
+
Rake to generate those that don't exist.
|
94
|
+
|
95
|
+
## Testing
|
96
|
+
|
97
|
+
`bundle exec rspec` runs tests. A minimal sample Jekyll site for tests to call on is in `spec/fixtures`,
|
98
|
+
with the interesting details being the sample templates in `spec/fixtures/layouts`.
|
data/files/rite.png
ADDED
Binary file
|
@@ -0,0 +1,23 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
require "jekyll-lilypond/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.version = "0.1.1"
|
8
|
+
spec.authors = "Leah Velleman"
|
9
|
+
spec.name = "jekyll-lilypond"
|
10
|
+
spec.summary = "Lilypond music snippets in Jekyll"
|
11
|
+
spec.homepage = "https://www.velleman.org/jekyll-lilypond.html"
|
12
|
+
spec.license = "MIT"
|
13
|
+
spec.files = `git ls-files -z`.split("\x0")
|
14
|
+
spec.metadata = {
|
15
|
+
"documentation_uri" => "https://www.velleman.org/jekyll-lilypond.html",
|
16
|
+
"source_code_uri" => "https://github.com/leahvelleman/jekyll-lilypond"
|
17
|
+
}
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
spec.add_dependency "jekyll", ">= 3.0", "< 5.0"
|
20
|
+
spec.add_development_dependency "rspec", "~> 3.5"
|
21
|
+
end
|
22
|
+
|
23
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "digest"
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Lilypond
|
5
|
+
class FileProcessor
|
6
|
+
def initialize(working_dir, hash, source)
|
7
|
+
@hash = hash
|
8
|
+
@source = source
|
9
|
+
@working_dir = working_dir
|
10
|
+
end
|
11
|
+
|
12
|
+
def filepath
|
13
|
+
"#{@working_dir}/#{@hash}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def write
|
17
|
+
unless File.directory?(@working_dir)
|
18
|
+
FileUtils.mkdir_p(@working_dir)
|
19
|
+
end
|
20
|
+
unless File.exist?("#{filepath}.ly")
|
21
|
+
File.open("#{filepath}.ly", "w") do |f|
|
22
|
+
f.write(@source)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def compile
|
28
|
+
unless File.exist?("#{filepath}.svg")
|
29
|
+
puts "Jekyll-lilypond: making #{@hash}.svg"
|
30
|
+
Kernel.system("lilypond", "-lERROR",
|
31
|
+
"-dbackend=svg",
|
32
|
+
"--output=#{filepath}",
|
33
|
+
"#{filepath}.ly")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def trim_svg
|
38
|
+
unless File.exist?("#{filepath}-trimmed.svg")
|
39
|
+
if File.exist?("#{filepath}.svg")
|
40
|
+
puts "Jekyll-lilypond: making #{@hash}-trimmed.svg"
|
41
|
+
Kernel.system("inkscape",
|
42
|
+
"#{filepath}.svg",
|
43
|
+
"--export-area-drawing",
|
44
|
+
"--export-type=svg",
|
45
|
+
"--export-filename=#{filepath}-trimmed.svg")
|
46
|
+
else
|
47
|
+
raise RuntimeError.new(
|
48
|
+
"Cannot trim SVG: expected SVG file #{filepath}.svg does not exist")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def make_mp3
|
54
|
+
unless File.exist?("#{filepath}.mp3")
|
55
|
+
if File.exist?("#{filepath}.midi")
|
56
|
+
puts "Jekyll-lilypond: making #{@hash}.mp3"
|
57
|
+
Kernel.system("timidity #{filepath}.midi -Ow -o - | ffmpeg -i - -acodec libmp3lame -ab 64k #{filepath}.mp3", [:out, :err] => "/dev/null")
|
58
|
+
else
|
59
|
+
raise RuntimeError.new(
|
60
|
+
"Cannot generate mp3: expected MIDI file #{filepath}.midi does not exist.")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module Lilypond
|
3
|
+
class LilypondTag < Liquid::Block
|
4
|
+
def initialize(_, argtext, _)
|
5
|
+
super
|
6
|
+
@attributes = parse_attributes(argtext)
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse_attributes(text)
|
10
|
+
attributes = {}
|
11
|
+
text.scan(Liquid::TagAttributes) do |key, value|
|
12
|
+
value=value.delete_prefix('"').delete_prefix("'")
|
13
|
+
value=value.delete_suffix('"').delete_suffix("'")
|
14
|
+
attributes[key] = value
|
15
|
+
end
|
16
|
+
attributes["attr_text"] = text
|
17
|
+
attributes
|
18
|
+
end
|
19
|
+
|
20
|
+
def render(context)
|
21
|
+
content = super.strip
|
22
|
+
site = context.registers[:site]
|
23
|
+
|
24
|
+
tag = Tag.new(@attributes, content)
|
25
|
+
tp = TagProcessor.new(site, tag)
|
26
|
+
tp.run!
|
27
|
+
tp.include
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Liquid::Template.register_tag("lilypond", Jekyll::Lilypond::LilypondTag)
|
34
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module Lilypond
|
3
|
+
class Tag
|
4
|
+
attr_accessor :attrs, :template_names, :template_code
|
5
|
+
|
6
|
+
def initialize(attrs, content)
|
7
|
+
@attrs = attrs
|
8
|
+
@attrs["content"] = content
|
9
|
+
@template_names = { source: @attrs.delete("source_template"),
|
10
|
+
include: @attrs.delete("include_template") }
|
11
|
+
@template_code = { source: @attrs.delete("source_template_code"),
|
12
|
+
include: @attrs.delete("include_template_code") }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module Lilypond
|
3
|
+
class TagProcessor
|
4
|
+
attr_accessor :site
|
5
|
+
|
6
|
+
def initialize(site, tag)
|
7
|
+
@site = site
|
8
|
+
@tag = tag
|
9
|
+
end
|
10
|
+
|
11
|
+
def source
|
12
|
+
source_template_obj.render(@tag)
|
13
|
+
end
|
14
|
+
|
15
|
+
def source_template_obj
|
16
|
+
Template.new(@site, @tag, :source)
|
17
|
+
end
|
18
|
+
|
19
|
+
def hash
|
20
|
+
Digest::MD5.hexdigest(source)
|
21
|
+
end
|
22
|
+
|
23
|
+
def include
|
24
|
+
@tag.attrs.update("filename" => hash)
|
25
|
+
include_template_obj.render(@tag)
|
26
|
+
end
|
27
|
+
|
28
|
+
def include_template_obj
|
29
|
+
Template.new(@site, @tag, :include)
|
30
|
+
end
|
31
|
+
|
32
|
+
def file_processor
|
33
|
+
FileProcessor.new("#{site.source}/lilypond_files", hash, source)
|
34
|
+
end
|
35
|
+
|
36
|
+
def run!
|
37
|
+
fp = file_processor
|
38
|
+
fp.write
|
39
|
+
fp.compile
|
40
|
+
fp.trim_svg
|
41
|
+
fp.make_mp3 if @tag.attrs["mp3"] == "true"
|
42
|
+
|
43
|
+
@site.static_files << StaticFile.new(site,
|
44
|
+
site.source,
|
45
|
+
"lilypond_files",
|
46
|
+
"#{hash}-trimmed.svg")
|
47
|
+
|
48
|
+
@site.static_files << StaticFile.new(site,
|
49
|
+
site.source,
|
50
|
+
"lilypond_files",
|
51
|
+
"#{hash}.mp3") if @tag.attrs["mp3"] == "true"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
\version "2.20.0"
|
2
|
+
\include "articulate.ly"
|
3
|
+
\paper {
|
4
|
+
indent = 0\mm
|
5
|
+
short-indent = 0\mm
|
6
|
+
{% if width %}
|
7
|
+
paper-width = {{ width }}\in
|
8
|
+
{% if height %}
|
9
|
+
paper-height = {{ height }}\in
|
10
|
+
{% else %}
|
11
|
+
page-breaking = #ly:one-page-breaking
|
12
|
+
{% endif %}
|
13
|
+
{% else %}
|
14
|
+
page-breaking = #ly:one-line-breaking
|
15
|
+
{% endif %}
|
16
|
+
left-margin = 4\mm
|
17
|
+
right-margin = 4\mm
|
18
|
+
top-margin = 4\mm
|
19
|
+
bottom-margin = 4\mm
|
20
|
+
oddHeaderMarkup = ##f
|
21
|
+
evenHeaderMarkup = ##f
|
22
|
+
oddFooterMarkup = ##f
|
23
|
+
evenFooterMarkup = ##f
|
24
|
+
}
|
25
|
+
\score {
|
26
|
+
\unfoldRepeats \articulate
|
27
|
+
<<
|
28
|
+
{{ content }}
|
29
|
+
>>
|
30
|
+
\layout {
|
31
|
+
#(layout-set-staff-size 16)
|
32
|
+
\context {
|
33
|
+
\Lyrics
|
34
|
+
{% if lyricfont %}
|
35
|
+
\override LyricText #'font-name = #"{{ lyricfont }}"
|
36
|
+
{% endif %}
|
37
|
+
{% if lyricsize %}
|
38
|
+
\override LyricText #'font-size = #{{ lyricsize }}
|
39
|
+
{% endif %}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
\midi {
|
43
|
+
\tempo 4 = {{ tempo | default: "120" }}
|
44
|
+
}
|
45
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
{{ content }}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<figure>
|
2
|
+
<img
|
3
|
+
src="lilypond_files/{{ filename }}-trimmed.svg"
|
4
|
+
{%- if style %}
|
5
|
+
style="{{ style }}"
|
6
|
+
{% endif -%}
|
7
|
+
{%- if class %}
|
8
|
+
class="{{ class }}"
|
9
|
+
{% endif -%}
|
10
|
+
{%- if alt %}
|
11
|
+
alt="{{ alt }}"
|
12
|
+
title="{{ alt }}"
|
13
|
+
{% endif -%}
|
14
|
+
/>
|
15
|
+
{%- if mp3 %}
|
16
|
+
<audio controls>
|
17
|
+
<source src="lilypond_files/{{ filename }}.mp3" type="audio/mp3" />
|
18
|
+
Your browser does not support the <code>audio</code> element.
|
19
|
+
</audio>
|
20
|
+
{% endif -%}
|
21
|
+
{%- if caption %}
|
22
|
+
<figcaption>{{ caption }}</figcaption>
|
23
|
+
{% endif -%}
|
24
|
+
</figure>
|
25
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
{{ content }}
|
@@ -0,0 +1 @@
|
|
1
|
+
{{ content }}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<figure
|
2
|
+
{%- if style %}
|
3
|
+
style="{{ style }}"
|
4
|
+
{% endif -%}
|
5
|
+
{%- if class %}
|
6
|
+
class="{{ class }}"
|
7
|
+
{% endif -%}
|
8
|
+
>
|
9
|
+
<img src="lilypond_files/{{ filename }}-trimmed.svg"
|
10
|
+
{%- if alt %}
|
11
|
+
alt="{{ alt }}"
|
12
|
+
title="{{ alt }}"
|
13
|
+
{% endif -%}
|
14
|
+
/>
|
15
|
+
{%- if mp3 %}
|
16
|
+
<audio controls>
|
17
|
+
<source src="lilypond_files/{{ filename }}.mp3" type="audio/mp3" />
|
18
|
+
Your browser does not support the <code>audio</code> element.
|
19
|
+
</audio>
|
20
|
+
{% endif -%}
|
21
|
+
{%- if caption %}
|
22
|
+
<figcaption>{{ caption }}</figcaption>
|
23
|
+
{% endif -%}
|
24
|
+
<details>
|
25
|
+
<summary>Show source</summary>
|
26
|
+
<pre>
|
27
|
+
{%- raw -%}{% {% endraw %}
|
28
|
+
lilypond {{ attr_text -}}
|
29
|
+
{%- raw %}%}{% endraw %}
|
30
|
+
{{ content | escape -}}
|
31
|
+
{%- raw -%}
|
32
|
+
{% endlilypond %}
|
33
|
+
{% endraw %}
|
34
|
+
</pre>
|
35
|
+
</details>
|
36
|
+
</figure>
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module Lilypond
|
3
|
+
class Template
|
4
|
+
def initialize(site, tag, type)
|
5
|
+
@site = site
|
6
|
+
@type = type
|
7
|
+
@tag_template_names = tag.template_names
|
8
|
+
@tag_template_code = tag.template_code
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(tag)
|
12
|
+
Liquid::Template.parse(template_code).render(tag.attrs)
|
13
|
+
end
|
14
|
+
|
15
|
+
def template_name
|
16
|
+
@tag_template_names[@type] || sitewide_template_names[@type] || plugin_template_names[@type]
|
17
|
+
end
|
18
|
+
|
19
|
+
def template_code
|
20
|
+
@tag_template_code[@type] or
|
21
|
+
fetch_site_template(template_name) or
|
22
|
+
fetch_plugin_template(template_name) or
|
23
|
+
raise LoadError.new("No template named #{template_name}.#{extension}")
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
private
|
28
|
+
def sitewide_template_names
|
29
|
+
if @site.respond_to? :lilypond and @site.lilypond.respond_to? :template_names
|
30
|
+
@site.lilypond.template_names
|
31
|
+
else
|
32
|
+
{ source: nil, include: nil }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def plugin_template_names
|
37
|
+
{ source: "basic", include: "img" }
|
38
|
+
end
|
39
|
+
|
40
|
+
def fetch_site_template(name)
|
41
|
+
if @site.layouts[name]
|
42
|
+
@site.layouts[name].content.strip
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch_plugin_template(name)
|
47
|
+
dir = File.join(File.dirname(__dir__), "/jekyll-lilypond/templates/")
|
48
|
+
filename = File.join(dir, "#{name}.#{extension}")
|
49
|
+
if File.exists?(filename)
|
50
|
+
File.read(filename).strip
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def extension
|
55
|
+
if @type == :source then "ly" else "html" end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "jekyll"
|
2
|
+
require "jekyll-lilypond/tag.rb"
|
3
|
+
require "jekyll-lilypond/file_processor.rb"
|
4
|
+
require "jekyll-lilypond/templates.rb"
|
5
|
+
require "jekyll-lilypond/tag_processor.rb"
|
6
|
+
require "jekyll-lilypond/lilypond_tag.rb"
|
7
|
+
|
8
|
+
module Jekyll
|
9
|
+
module Lilypond
|
10
|
+
end
|
11
|
+
end
|