clef 0.1.0 → 1.0.0

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +77 -90
  3. data/Rakefile +21 -1
  4. data/exe/clef +21 -0
  5. data/lib/clef/compiler.rb +107 -4
  6. data/lib/clef/core/chord.rb +9 -3
  7. data/lib/clef/core/duration.rb +7 -3
  8. data/lib/clef/core/key_signature.rb +43 -36
  9. data/lib/clef/core/measure.rb +14 -10
  10. data/lib/clef/core/metadata.rb +52 -0
  11. data/lib/clef/core/note.rb +50 -4
  12. data/lib/clef/core/pitch.rb +73 -4
  13. data/lib/clef/core/rest.rb +11 -3
  14. data/lib/clef/core/score.rb +148 -9
  15. data/lib/clef/core/staff.rb +13 -3
  16. data/lib/clef/core/staff_group.rb +8 -2
  17. data/lib/clef/core/tempo.rb +5 -0
  18. data/lib/clef/core/tuplet.rb +48 -0
  19. data/lib/clef/core/validation.rb +39 -0
  20. data/lib/clef/core/voice.rb +21 -5
  21. data/lib/clef/engraving/font_manager.rb +1 -1
  22. data/lib/clef/engraving/glyph_table.rb +18 -3
  23. data/lib/clef/engraving/style.rb +41 -2
  24. data/lib/clef/ir/moment.rb +2 -2
  25. data/lib/clef/ir/music_tree.rb +2 -2
  26. data/lib/clef/ir/timeline.rb +25 -5
  27. data/lib/clef/layout/beam_layout.rb +2 -2
  28. data/lib/clef/layout/item.rb +26 -0
  29. data/lib/clef/layout/spacing.rb +6 -4
  30. data/lib/clef/layout/stem.rb +10 -6
  31. data/lib/clef/layout/system_layout.rb +71 -0
  32. data/lib/clef/midi/channel_map.rb +5 -2
  33. data/lib/clef/midi/exporter.rb +316 -38
  34. data/lib/clef/notation/dynamic.rb +5 -0
  35. data/lib/clef/notation/lyric.rb +33 -1
  36. data/lib/clef/parser/dsl.rb +249 -58
  37. data/lib/clef/parser/lilypond_lexer.rb +43 -3
  38. data/lib/clef/parser/lilypond_parser.rb +231 -17
  39. data/lib/clef/plugins/base.rb +24 -4
  40. data/lib/clef/plugins/registry.rb +80 -10
  41. data/lib/clef/renderer/base.rb +2 -2
  42. data/lib/clef/renderer/drawing_context.rb +26 -0
  43. data/lib/clef/renderer/notation_helpers.rb +92 -1
  44. data/lib/clef/renderer/pdf_renderer.rb +487 -82
  45. data/lib/clef/renderer/svg_renderer.rb +510 -97
  46. data/lib/clef/version.rb +1 -1
  47. data/lib/clef.rb +60 -7
  48. data/sig/clef.rbs +292 -0
  49. metadata +14 -5
data/lib/clef/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Clef
4
- VERSION = "0.1.0"
4
+ VERSION = "1.0.0"
5
5
  end
data/lib/clef.rb CHANGED
@@ -1,20 +1,73 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "clef/version"
4
- Dir[File.expand_path("clef/**/*.rb", __dir__)].sort.each do |file|
5
- require file unless file.end_with?("version.rb")
6
- end
4
+ require_relative "clef/core/duration"
5
+ require_relative "clef/core/pitch"
6
+ require_relative "clef/core/time_signature"
7
+ require_relative "clef/core/tempo"
8
+ require_relative "clef/core/clef"
9
+ require_relative "clef/core/key_signature"
10
+ require_relative "clef/core/note"
11
+ require_relative "clef/core/rest"
12
+ require_relative "clef/core/chord"
13
+ require_relative "clef/core/tuplet"
14
+ require_relative "clef/core/voice"
15
+ require_relative "clef/core/measure"
16
+ require_relative "clef/core/metadata"
17
+ require_relative "clef/core/staff"
18
+ require_relative "clef/core/staff_group"
19
+ require_relative "clef/core/validation"
20
+ require_relative "clef/core/score"
21
+ require_relative "clef/notation/articulation"
22
+ require_relative "clef/notation/barline"
23
+ require_relative "clef/notation/beam"
24
+ require_relative "clef/notation/dynamic"
25
+ require_relative "clef/notation/lyric"
26
+ require_relative "clef/notation/slur"
27
+ require_relative "clef/notation/tie"
28
+ require_relative "clef/engraving/rules"
29
+ require_relative "clef/engraving/style"
30
+ require_relative "clef/engraving/glyph_table"
31
+ require_relative "clef/engraving/font_manager"
32
+ require_relative "clef/ir/moment"
33
+ require_relative "clef/ir/event"
34
+ require_relative "clef/ir/timeline"
35
+ require_relative "clef/ir/music_tree"
36
+ require_relative "clef/layout/beam_layout"
37
+ require_relative "clef/layout/item"
38
+ require_relative "clef/layout/line_breaker"
39
+ require_relative "clef/layout/page_breaker"
40
+ require_relative "clef/layout/spacing"
41
+ require_relative "clef/layout/stem"
42
+ require_relative "clef/layout/system_layout"
43
+ require_relative "clef/plugins/base"
44
+ require_relative "clef/plugins/registry"
45
+ require_relative "clef/renderer/base"
46
+ require_relative "clef/renderer/drawing_context"
47
+ require_relative "clef/renderer/notation_helpers"
48
+ require_relative "clef/renderer/pdf_renderer"
49
+ require_relative "clef/renderer/svg_renderer"
50
+ require_relative "clef/midi/channel_map"
51
+ require_relative "clef/midi/exporter"
52
+ require_relative "clef/parser/lilypond_lexer"
53
+ require_relative "clef/parser/dsl"
54
+ require_relative "clef/parser/lilypond_parser"
55
+ require_relative "clef/compiler"
7
56
 
8
57
  module Clef
9
58
  class Error < StandardError; end
10
59
 
11
60
  class << self
61
+ attr_reader :last_score
62
+
12
63
  # @yield DSL block
13
64
  # @return [Clef::Core::Score]
14
- def score(&block)
15
- builder = Clef::Parser::DSL::ScoreBuilder.new
16
- builder.instance_eval(&block) if block
17
- builder.build
65
+ def score(plugins: Clef.plugins, &block)
66
+ builder = Clef::Parser::DSL::ScoreBuilder.new(plugins: plugins)
67
+ if block
68
+ (block.arity == 1) ? block.call(builder) : builder.instance_eval(&block)
69
+ end
70
+ @last_score = builder.build
18
71
  end
19
72
 
20
73
  # @return [Clef::Plugins::Registry]
data/sig/clef.rbs ADDED
@@ -0,0 +1,292 @@
1
+ module Clef
2
+ VERSION: String
3
+
4
+ def self.score: (?plugins: Plugins::Registry) { (Parser::DSL::ScoreBuilder) -> void } -> Core::Score
5
+ | (?plugins: Plugins::Registry) { () -> void } -> Core::Score
6
+ | (?plugins: Plugins::Registry) -> Core::Score
7
+ def self.last_score: () -> Core::Score?
8
+ def self.plugins: () -> Plugins::Registry
9
+
10
+ class Error < StandardError
11
+ end
12
+
13
+ class Compiler
14
+ def initialize: (Core::Score score, ?style: Engraving::Style, ?plugins: Plugins::Registry) -> void
15
+ def compile_to_pdf: (untyped path) -> untyped
16
+ def compile_to_svg: (untyped path) -> untyped
17
+ end
18
+
19
+ module Core
20
+ class Chord
21
+ attr_reader pitches: Array[Pitch]
22
+ attr_reader duration: Duration
23
+
24
+ def initialize: (Array[Pitch] pitches, Duration duration) -> void
25
+ def length: () -> Rational
26
+ def sorted_pitches: () -> Array[Pitch]
27
+ end
28
+
29
+ class Clef
30
+ attr_reader type: Symbol
31
+
32
+ def initialize: (?Symbol type) -> void
33
+ def reference_pitch: () -> Pitch
34
+ def reference_line: () -> Integer
35
+ end
36
+
37
+ class Duration
38
+ attr_reader base: Symbol
39
+ attr_reader dots: Integer
40
+
41
+ def initialize: (Symbol base, ?dots: Integer) -> void
42
+ def self.from_lilypond: (Integer number, ?Integer dots) -> Duration
43
+ def self.whole: () -> Duration
44
+ def self.half: () -> Duration
45
+ def self.quarter: () -> Duration
46
+ def self.eighth: () -> Duration
47
+ def self.sixteenth: () -> Duration
48
+ def self.thirty_second: () -> Duration
49
+ def self.sixty_fourth: () -> Duration
50
+ def self.one_twenty_eighth: () -> Duration
51
+ def self.two_fifty_sixth: () -> Duration
52
+
53
+ def base_value: () -> Rational
54
+ def length: () -> Rational
55
+ def to_lilypond: () -> String
56
+ end
57
+
58
+ class KeySignature
59
+ attr_reader tonic: Pitch
60
+ attr_reader mode: Symbol
61
+
62
+ def initialize: (Pitch | Symbol | String tonic, ?Symbol mode) -> void
63
+ def accidentals: () -> Hash[Symbol, Symbol | Integer]
64
+ def preferred_transpose_spelling: () -> Symbol
65
+ end
66
+
67
+ class Measure
68
+ attr_reader number: Integer
69
+ attr_reader voices: Hash[Symbol, Voice]
70
+ attr_accessor key_signature: KeySignature?
71
+ attr_accessor time_signature: TimeSignature?
72
+ attr_accessor clef: Clef?
73
+
74
+ def initialize: (Integer number, ?time_signature: TimeSignature?) -> void
75
+ def voice: (?Symbol id) { (Voice) -> void } -> Voice
76
+ | (?Symbol id) -> Voice
77
+ def overflowing_voice_ids: () -> Array[Symbol]
78
+ def underfull_voice_ids: () -> Array[Symbol]
79
+ end
80
+
81
+ class Note
82
+ attr_reader pitch: Pitch
83
+ attr_reader duration: Duration
84
+ attr_reader tie_state: Symbol?
85
+ attr_reader articulations: Array[Symbol]
86
+ attr_accessor slur_start: bool
87
+ attr_accessor slur_end: bool
88
+ attr_accessor beam_start: bool
89
+ attr_accessor beam_end: bool
90
+
91
+ def initialize: (Pitch pitch, Duration duration, ?articulations: Array[Symbol], ?tied: bool | Symbol?) -> void
92
+ def length: () -> Rational
93
+ def tied: () -> bool
94
+ def tied=: (bool | Symbol? value) -> bool | Symbol?
95
+ def articulations=: (Array[Symbol] values) -> Array[Symbol]
96
+ def add_articulation: (Symbol articulation) -> Note
97
+ end
98
+
99
+ class Pitch
100
+ attr_reader note_name: Symbol
101
+ attr_reader octave: Integer
102
+ attr_reader alteration: Integer
103
+
104
+ def initialize: (Symbol note_name, Integer octave, ?alteration: Integer) -> void
105
+ def self.parse: (String str) -> Pitch
106
+ def self.parse_scientific: (String str) -> Pitch
107
+ def self.parse_any: (String | Symbol | Pitch value) -> Pitch
108
+
109
+ def to_lilypond: () -> String
110
+ def to_midi: () -> Integer
111
+ def semitones: () -> Integer
112
+ def to_frequency: (?tuning: Float) -> Float
113
+ def transpose: (untyped semitones_or_interval, ?prefer: Symbol?, ?key_signature: KeySignature?) -> Pitch
114
+ def enharmonic?: (untyped other) -> bool
115
+ end
116
+
117
+ class Rest
118
+ attr_reader duration: Duration
119
+ attr_reader kind: Symbol
120
+ attr_reader measures: Integer
121
+
122
+ def initialize: (Duration duration, ?kind: Symbol, ?measures: Integer) -> void
123
+ def length: () -> Rational
124
+ end
125
+
126
+ class Score
127
+ attr_reader staff_groups: Array[StaffGroup]
128
+ attr_reader metadata: Hash[untyped, untyped]
129
+ attr_accessor title: String?
130
+ attr_accessor composer: String?
131
+ attr_accessor tempo: Tempo?
132
+ attr_accessor plugins: Plugins::Registry?
133
+
134
+ def initialize: (?metadata: Hash[untyped, untyped]) -> void
135
+ def metadata=: (Hash[untyped, untyped] value) -> Hash[untyped, untyped]
136
+ def set_metadata: (untyped key, untyped value) -> Score
137
+ def update_metadata: (?Hash[untyped, untyped] value, **untyped kwargs) -> Score
138
+ def add_staff_group: (StaffGroup staff_group) -> Score
139
+ def add_staff: (Staff staff) -> Score
140
+ def staves: () -> Array[Staff]
141
+ def to_pdf: (untyped path, **untyped options) -> untyped
142
+ def to_svg: (untyped path, **untyped options) -> untyped
143
+ def to_midi: (untyped path, **untyped options) -> untyped
144
+ def to_format: (untyped path, **untyped options) -> untyped
145
+ def validate: (?strict: bool) -> ValidationResult
146
+ def validation_warnings: () -> Array[ValidationIssue]
147
+ end
148
+
149
+ class Staff
150
+ attr_reader id: Symbol
151
+ attr_reader name: String
152
+ attr_reader clef: Clef
153
+ attr_reader measures: Array[Measure]
154
+ attr_reader metadata: Hash[untyped, untyped]
155
+ attr_accessor key_signature: KeySignature?
156
+ attr_accessor time_signature: TimeSignature?
157
+
158
+ def initialize: (Symbol id, ?name: String?, ?clef: Clef) -> void
159
+ def metadata=: (Hash[untyped, untyped] value) -> Hash[untyped, untyped]
160
+ def set_metadata: (untyped key, untyped value) -> Staff
161
+ def update_metadata: (?Hash[untyped, untyped] value, **untyped kwargs) -> Staff
162
+ def add_measure: (Measure measure) -> Staff
163
+ end
164
+
165
+ class StaffGroup
166
+ attr_reader staves: Array[Staff]
167
+ attr_reader bracket_type: Symbol
168
+
169
+ def initialize: (?Array[Staff] staves, ?bracket_type: Symbol) -> void
170
+ def add_staff: (Staff staff) -> StaffGroup
171
+ end
172
+
173
+ class Tempo
174
+ attr_reader beat_unit: Duration
175
+ attr_reader bpm: Integer
176
+
177
+ def initialize: (beat_unit: Duration, bpm: Integer) -> void
178
+ def length: () -> Rational
179
+ end
180
+
181
+ class TimeSignature
182
+ attr_reader numerator: Integer
183
+ attr_reader denominator: Integer
184
+
185
+ def initialize: (Integer numerator, Integer denominator) -> void
186
+ def measure_length: () -> Rational
187
+ end
188
+
189
+ class Tuplet
190
+ attr_reader actual: Integer
191
+ attr_reader normal: Integer
192
+ attr_reader elements: Array[Note | Rest | Chord | Tuplet]
193
+
194
+ def initialize: (Integer actual, Integer normal, Array[Note | Rest | Chord | Tuplet] elements) -> void
195
+ def length: () -> Rational
196
+ def ratio: () -> Rational
197
+ end
198
+
199
+ class ValidationIssue
200
+ attr_accessor severity: Symbol
201
+ attr_accessor message: String
202
+ attr_accessor path: Array[untyped]
203
+
204
+ def warning?: () -> bool
205
+ def error?: () -> bool
206
+ end
207
+
208
+ class ValidationResult
209
+ attr_reader issues: Array[ValidationIssue]
210
+
211
+ def initialize: (?Array[ValidationIssue] issues) -> void
212
+ def ok?: () -> bool
213
+ def errors: () -> Array[ValidationIssue]
214
+ def warnings: () -> Array[ValidationIssue]
215
+ end
216
+
217
+ class Voice
218
+ attr_reader id: Symbol
219
+ attr_reader elements: Array[untyped]
220
+
221
+ def initialize: (?id: Symbol) -> void
222
+ def add: (untyped element) -> Voice
223
+ def total_length: () -> Rational
224
+ end
225
+ end
226
+
227
+ module Midi
228
+ class Exporter
229
+ attr_reader score: Core::Score
230
+ attr_reader ppqn: Integer
231
+ attr_reader instrument_map: Hash[untyped, untyped]
232
+ attr_reader plugins: Plugins::Registry
233
+
234
+ def initialize: (Core::Score score, ?channel_map: ChannelMap, ?ppqn: Integer, ?instrument_map: Hash[untyped, untyped], ?plugins: Plugins::Registry) -> void
235
+ def export: (untyped target) -> untyped
236
+ end
237
+ end
238
+
239
+ module Notation
240
+ class Lyric
241
+ attr_reader voice_id: Symbol
242
+ attr_reader text: String
243
+ attr_reader syllables: Array[String]
244
+
245
+ def initialize: (Symbol voice_id, String text) -> void
246
+ def note_slot_count: () -> Integer
247
+ def self.note_syllable?: (String syllable) -> bool
248
+ def self.hyphen?: (String syllable) -> bool
249
+ def self.extender?: (String syllable) -> bool
250
+ end
251
+ end
252
+
253
+ module Parser
254
+ class LilypondParser
255
+ attr_reader warnings: Array[String]
256
+ attr_reader plugins: Plugins::Registry
257
+
258
+ def initialize: (?plugins: Plugins::Registry) -> void
259
+ def parse: (String input) -> Core::Score
260
+ end
261
+
262
+ module DSL
263
+ class Error < StandardError
264
+ end
265
+
266
+ class ScoreBuilder
267
+ attr_reader score: Core::Score
268
+ end
269
+ end
270
+ end
271
+
272
+ module Plugins
273
+ class Base
274
+ end
275
+
276
+ class Registry
277
+ attr_reader errors: Array[Hash[Symbol, untyped]]
278
+
279
+ def initialize: (?error_policy: Symbol) -> void
280
+ def plugins: () -> Array[Base]
281
+ def register: (Class | Base plugin_or_class, *untyped args, ?priority: Integer, **untyped kwargs) -> Base
282
+ def unregister: (Class | Base | String | Symbol plugin_or_class) -> Base?
283
+ def clear: () -> Array[untyped]
284
+ def run_hook: (Symbol hook_name, *untyped args) -> Array[untyped]
285
+ end
286
+ end
287
+
288
+ module Engraving
289
+ class Style
290
+ end
291
+ end
292
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clef
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yudai Takada
@@ -51,11 +51,12 @@ dependencies:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
53
  version: '4.0'
54
- description: Clef provides a Ruby DSL, LilyPond-like note input, and basic LilyPond
55
- parsing for modeling simple scores and exporting them to PDF, SVG, or MIDI.
54
+ description: Clef provides a Ruby DSL, LilyPond-style note input, and a small LilyPond-style
55
+ syntax parser for modeling simple scores and exporting them to PDF, SVG, or MIDI.
56
56
  email:
57
57
  - t.yudai92@gmail.com
58
- executables: []
58
+ executables:
59
+ - clef
59
60
  extensions: []
60
61
  extra_rdoc_files: []
61
62
  files:
@@ -66,6 +67,7 @@ files:
66
67
  - examples/piano_score.rb
67
68
  - examples/twinkle.rb
68
69
  - examples/vocal_score.rb
70
+ - exe/clef
69
71
  - fonts/bravura/README.md
70
72
  - lib/clef.rb
71
73
  - lib/clef/compiler.rb
@@ -74,6 +76,7 @@ files:
74
76
  - lib/clef/core/duration.rb
75
77
  - lib/clef/core/key_signature.rb
76
78
  - lib/clef/core/measure.rb
79
+ - lib/clef/core/metadata.rb
77
80
  - lib/clef/core/note.rb
78
81
  - lib/clef/core/pitch.rb
79
82
  - lib/clef/core/rest.rb
@@ -82,6 +85,8 @@ files:
82
85
  - lib/clef/core/staff_group.rb
83
86
  - lib/clef/core/tempo.rb
84
87
  - lib/clef/core/time_signature.rb
88
+ - lib/clef/core/tuplet.rb
89
+ - lib/clef/core/validation.rb
85
90
  - lib/clef/core/voice.rb
86
91
  - lib/clef/engraving/font_manager.rb
87
92
  - lib/clef/engraving/glyph_table.rb
@@ -92,10 +97,12 @@ files:
92
97
  - lib/clef/ir/music_tree.rb
93
98
  - lib/clef/ir/timeline.rb
94
99
  - lib/clef/layout/beam_layout.rb
100
+ - lib/clef/layout/item.rb
95
101
  - lib/clef/layout/line_breaker.rb
96
102
  - lib/clef/layout/page_breaker.rb
97
103
  - lib/clef/layout/spacing.rb
98
104
  - lib/clef/layout/stem.rb
105
+ - lib/clef/layout/system_layout.rb
99
106
  - lib/clef/midi/channel_map.rb
100
107
  - lib/clef/midi/exporter.rb
101
108
  - lib/clef/notation/articulation.rb
@@ -111,16 +118,18 @@ files:
111
118
  - lib/clef/plugins/base.rb
112
119
  - lib/clef/plugins/registry.rb
113
120
  - lib/clef/renderer/base.rb
121
+ - lib/clef/renderer/drawing_context.rb
114
122
  - lib/clef/renderer/notation_helpers.rb
115
123
  - lib/clef/renderer/pdf_renderer.rb
116
124
  - lib/clef/renderer/svg_renderer.rb
117
125
  - lib/clef/version.rb
126
+ - sig/clef.rbs
118
127
  homepage: https://github.com/ydah/clef
119
128
  licenses:
120
129
  - MIT
121
130
  metadata:
122
- homepage_uri: https://github.com/ydah/clef
123
131
  source_code_uri: https://github.com/ydah/clef
132
+ rubygems_mfa_required: 'true'
124
133
  rdoc_options: []
125
134
  require_paths:
126
135
  - lib