LilyPond-Ruby 0.0.2.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/guile.rb +19 -0
- data/lib/lilypond/builder.rb +161 -0
- data/lib/lilypond-ruby.rb +18 -3
- metadata +28 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd7caa18b5b13373b5d316f0b09ad3575131816a2a5c3190c4b4564cf5ebd3da
|
4
|
+
data.tar.gz: fe45f4258930993b960751c9c25157f695aa822ba651fd66c331dbf03faae8a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2430168be722d01a3a1cb3d6e79d146a86a8e2790d0a1b875e2fc1a23b2778c7b0a6c4cddd2dd2ca4912b9996c05168b1252a80131513a2e55d627172031fb08
|
7
|
+
data.tar.gz: cdf33ac9fd098add59a5050d0fe95f13ef09b0f3e2bf1d957e71bcc175d9741e76900a1f4f17e36555d261dc467d7a47fcee5d5333c897e5a0006eee0750eff1
|
data/lib/guile.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Guile
|
4
|
+
extend FFI::Library
|
5
|
+
|
6
|
+
# Load the Guile shared library
|
7
|
+
ffi_lib 'libguile-2.2.so.1'
|
8
|
+
|
9
|
+
# Define the Guile functions we want to call
|
10
|
+
attach_function :scm_init_guile, [:int], :void
|
11
|
+
attach_function :scm_c_eval_string, [:string], :void
|
12
|
+
end
|
13
|
+
|
14
|
+
# Initialize Guile
|
15
|
+
Guile.scm_init_guile(0)
|
16
|
+
|
17
|
+
# Evaluate a Guile script
|
18
|
+
Guile.scm_c_eval_string('(display "Hello, Guile!")')
|
19
|
+
puts "\n"
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require_relative "../lilypond-ruby.rb"
|
2
|
+
|
3
|
+
# The LilyPond class provides an interface for generating LilyPond notation.
|
4
|
+
class LilyPond
|
5
|
+
# The Builder class is responsible for building LilyPond notation.
|
6
|
+
class Builder
|
7
|
+
# Creates a new LilyPond Builder object.
|
8
|
+
def initialize
|
9
|
+
@buffer = "\\version \"#{LilyPond.version_number}\"\n"
|
10
|
+
@indent_level = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns the current indentation level.
|
14
|
+
#
|
15
|
+
# @return [String] the current indentation level in spaces
|
16
|
+
def indent
|
17
|
+
" " * @indent_level * 2
|
18
|
+
end
|
19
|
+
|
20
|
+
# Generates a block of LilyPond notation.
|
21
|
+
#
|
22
|
+
# @param name [String] the name of the block
|
23
|
+
# @param parallel [Boolean] whether the block should be parallel
|
24
|
+
# @param options [Hash] the options for the block
|
25
|
+
# @yield the block content
|
26
|
+
def block(name = nil, parallel = false, options = {})
|
27
|
+
@buffer << "#{indent}"
|
28
|
+
@buffer << "\\#{name} " unless name == nil
|
29
|
+
if options.any?
|
30
|
+
@buffer << "\\with { \n"
|
31
|
+
@indent_level +=1
|
32
|
+
options.each do |key, value|
|
33
|
+
@buffer << "#{indent}#{key.to_s.camelize_lower} = #"
|
34
|
+
@buffer << (value.class.name == "String" ? "\"#{value}\"" : "#{value}")
|
35
|
+
@buffer << "\n"
|
36
|
+
end
|
37
|
+
@indent_level -=1
|
38
|
+
@buffer << "#{indent}} "
|
39
|
+
end
|
40
|
+
@buffer << "#{parallel ? "<<" : "{" }"
|
41
|
+
if block_given?
|
42
|
+
@buffer << "\n"
|
43
|
+
@indent_level += 1
|
44
|
+
yield
|
45
|
+
@indent_level -= 1
|
46
|
+
@buffer << "#{indent}#{parallel ? ">>" : "}" }\n"
|
47
|
+
else
|
48
|
+
@buffer << "#{parallel ? ">>" : "}" }\n"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Defines the content for a LilyPond variable.
|
53
|
+
#
|
54
|
+
# @param variable_name [String] the name of the variable
|
55
|
+
# @param lyricmode [Boolean] whether the variable should be in lyric mode
|
56
|
+
# @yield the variable content
|
57
|
+
def define_content(variable_name = nil, lyricmode = false)
|
58
|
+
@buffer << "#{indent}"
|
59
|
+
@buffer << "#{variable_name} = " unless variable_name.nil?
|
60
|
+
@buffer << "\\lyricmode " if lyricmode
|
61
|
+
@buffer << "{\n"
|
62
|
+
@indent_level += 1
|
63
|
+
yield
|
64
|
+
@indent_level -= 1
|
65
|
+
@buffer << "}\n"
|
66
|
+
end
|
67
|
+
|
68
|
+
# Uses the content of a LilyPond variable.
|
69
|
+
#
|
70
|
+
# @param variable_name [String] the name of the variable to use
|
71
|
+
def use_content(variable_name)
|
72
|
+
@buffer << "#{indent}\\#{variable_name}\n"
|
73
|
+
end
|
74
|
+
|
75
|
+
# Appends a string of LilyPond notation to the buffer.
|
76
|
+
#
|
77
|
+
# @param string [String] the LilyPond notation to append
|
78
|
+
def append(string)
|
79
|
+
@buffer << "#{indent}#{string}\n"
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns the current buffer as a string of LilyPond notation.
|
83
|
+
#
|
84
|
+
# @return [String] the LilyPond notation buffer
|
85
|
+
def to_s
|
86
|
+
@buffer
|
87
|
+
end
|
88
|
+
|
89
|
+
class << self
|
90
|
+
# Generates a sample LilyPond notation.
|
91
|
+
#
|
92
|
+
# @return [LilyPond::Builder] the LilyPond notation builder
|
93
|
+
def sample
|
94
|
+
parallel = true
|
95
|
+
options = {
|
96
|
+
:midi_maximum_volume => 0.4,
|
97
|
+
:instrument_name => "Piano"
|
98
|
+
}
|
99
|
+
ly = LilyPond::Builder.new
|
100
|
+
|
101
|
+
ly.append "%% MUSIC %%"
|
102
|
+
ly.define_content("global") do |global|
|
103
|
+
ly.append "\\numericTimeSignature"
|
104
|
+
ly.append "\\time 4/4"
|
105
|
+
ly.append "s1 * 4 |"
|
106
|
+
ly.append "\\bar \"|.\""
|
107
|
+
end #global
|
108
|
+
ly.define_content("sopranoMusic") do |sopranoMusic|
|
109
|
+
ly.append "c'4 d'4 e'4 f'4 |"
|
110
|
+
ly.append "c'4 d'4 e'4 f'4 |"
|
111
|
+
ly.append "c'4 d'4 e'4 f'4 |"
|
112
|
+
ly.append "c'4 d'4 e'4 f'4 |"
|
113
|
+
end #sopranoMusic
|
114
|
+
ly.append "%% LYRICS %%"
|
115
|
+
ly.define_content("sopranoLyrics", true) do |sopranoLyrics|
|
116
|
+
ly.append "do re me fa"
|
117
|
+
ly.append "do re me fa"
|
118
|
+
ly.append "do re me fa"
|
119
|
+
ly.append "do re me fa"
|
120
|
+
end #sopranoLyrics
|
121
|
+
ly.append "%% BOOKS %%"
|
122
|
+
ly.block("book") do |book|
|
123
|
+
ly.block("score") do |score|
|
124
|
+
ly.block(nil, parallel) do |score_content|
|
125
|
+
ly.block("new Staff", parallel, options) do |staff|
|
126
|
+
ly.block("new Voice", parallel) do |voice|
|
127
|
+
ly.use_content("global")
|
128
|
+
ly.use_content("sopranoMusic")
|
129
|
+
end #voice
|
130
|
+
ly.block("new Lyrics") do |lyrics|
|
131
|
+
ly.use_content("sopranoLyrics")
|
132
|
+
end #lyrics
|
133
|
+
end #staff
|
134
|
+
end #score_content
|
135
|
+
ly.block("midi")
|
136
|
+
ly.block("layout")
|
137
|
+
end #score
|
138
|
+
end #book
|
139
|
+
|
140
|
+
return ly
|
141
|
+
end #sample()
|
142
|
+
|
143
|
+
end #self
|
144
|
+
end #Builder
|
145
|
+
end #LilyPond
|
146
|
+
|
147
|
+
# Adds a `camelize_lower` method to the String class.
|
148
|
+
class String
|
149
|
+
# Converts an underscored string to camel case, except the first word remains downcase.
|
150
|
+
#
|
151
|
+
# Examples
|
152
|
+
#
|
153
|
+
# "my_foo".camelize_lower #=> "myFoo"
|
154
|
+
#
|
155
|
+
# @return [String] the camelized string
|
156
|
+
def camelize_lower
|
157
|
+
self.split('_').map.with_index do |word, i|
|
158
|
+
i == 0 ? word.downcase : word.capitalize
|
159
|
+
end.join('')
|
160
|
+
end
|
161
|
+
end
|
data/lib/lilypond-ruby.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require "open3"
|
2
|
+
require "lilypond/builder"
|
3
|
+
require "guile"
|
2
4
|
|
3
5
|
class LilyPond
|
4
|
-
|
6
|
+
LILYPOND_PATH = File.expand_path("../../bin/lilypond", __FILE__)
|
5
7
|
class << self
|
6
8
|
|
7
9
|
def version
|
8
|
-
output, error, status = Open3.capture3(
|
10
|
+
output, error, status = Open3.capture3(LILYPOND_PATH, "--version")
|
9
11
|
if status.success?
|
10
12
|
puts output
|
11
13
|
else
|
@@ -13,8 +15,20 @@ class LilyPond
|
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
18
|
+
def version_number
|
19
|
+
output, error, status = Open3.capture3(LILYPOND_PATH, "--version")
|
20
|
+
if status.success?
|
21
|
+
return output.match(/GNU LilyPond (\d+\.\d+\.\d+)/)[1]
|
22
|
+
else
|
23
|
+
return "#{error}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
16
27
|
def generate_pdf_with_lilypond(file_name, lilypond_code)
|
17
|
-
|
28
|
+
tempfile = Tempfile.new(file_name)
|
29
|
+
tempfile.write(lilypond_code)
|
30
|
+
tempfile.close
|
31
|
+
Open3.popen3(LILYPOND_PATH, "--pdf", tempfile.path) do |stdin, stdout, stderr, wait_thr|
|
18
32
|
# Write the Lilypond code to stdin
|
19
33
|
stdin.write(lilypond_code)
|
20
34
|
stdin.close
|
@@ -42,6 +56,7 @@ class LilyPond
|
|
42
56
|
break
|
43
57
|
end
|
44
58
|
end
|
59
|
+
File.delete(tempfile.path)
|
45
60
|
end
|
46
61
|
|
47
62
|
end # end self
|
metadata
CHANGED
@@ -1,16 +1,38 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: LilyPond-Ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lee Whittaker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-03-
|
12
|
-
dependencies:
|
13
|
-
|
11
|
+
date: 2023-03-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.15'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.15.5
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.15'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.15.5
|
33
|
+
description: "This gem provides a library to access and control Lilypond within Ruby.\nIt
|
34
|
+
contains the libraries and binary files for LilyPond 2.24.1 and\nGuile 2.2.3. \n\n\nIt
|
35
|
+
also provides a builder tool for generating LilyPond files dynamically\nwith Ruby.\n"
|
14
36
|
email: whittakerlee81@gmail.com
|
15
37
|
executables:
|
16
38
|
- lilypond
|
@@ -27,7 +49,9 @@ files:
|
|
27
49
|
- bin/lilysong
|
28
50
|
- bin/midi2ly
|
29
51
|
- bin/musicxml2ly
|
52
|
+
- lib/guile.rb
|
30
53
|
- lib/lilypond-ruby.rb
|
54
|
+
- lib/lilypond/builder.rb
|
31
55
|
homepage: https://github.com/Okomikeruko/LilyPond-Ruby
|
32
56
|
licenses:
|
33
57
|
- MIT
|