alda-rb 0.1.4 → 0.2.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +1 -1
- data/Gemfile +4 -0
- data/README.md +2 -2
- data/Rakefile +15 -6
- data/bin/setup +1 -1
- data/examples/bwv846_prelude.rb +1 -1
- data/lib/alda-rb.rb +8 -1074
- data/lib/alda-rb/commandline.rb +139 -0
- data/lib/alda-rb/error.rb +80 -0
- data/lib/alda-rb/event.rb +983 -0
- data/lib/alda-rb/event_list.rb +313 -0
- data/lib/alda-rb/patches.rb +168 -0
- data/lib/alda-rb/repl.rb +245 -0
- data/lib/alda-rb/version.rb +7 -1
- metadata +8 -2
@@ -0,0 +1,139 @@
|
|
1
|
+
module Kernel
|
2
|
+
##
|
3
|
+
# :call-seq:
|
4
|
+
# alda(*args) -> true or false
|
5
|
+
#
|
6
|
+
# Runs the alda command.
|
7
|
+
# Does not capture output.
|
8
|
+
#
|
9
|
+
# alda 'version'
|
10
|
+
# alda 'play', '-c', 'piano: a'
|
11
|
+
# alda 'repl'
|
12
|
+
#
|
13
|
+
# Returns whether the exit status is +0+.
|
14
|
+
def alda *args
|
15
|
+
system Alda.executable, *args
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module Alda
|
20
|
+
|
21
|
+
##
|
22
|
+
# The array of available subcommands of alda executable.
|
23
|
+
#
|
24
|
+
# Alda is able to invoke +alda+ at the command line.
|
25
|
+
# The subcommand is the name of the method invoked upon Alda.
|
26
|
+
#
|
27
|
+
# The keyword arguments are interpreted as the subcommand options.
|
28
|
+
# To specify the command options, use ::[].
|
29
|
+
#
|
30
|
+
# The return value is the string output by the command in STDOUT.
|
31
|
+
#
|
32
|
+
# If the exit code is nonzero, an Alda::CommandLineError is raised.
|
33
|
+
#
|
34
|
+
# Alda.version
|
35
|
+
# # => "Client version: 1.4.0\nServer version: [27713] 1.4.0\n"
|
36
|
+
# Alda.parse code: 'bassoon: o3 c'
|
37
|
+
# # => "{\"chord-mode\":false,\"current-instruments\":...}\n"
|
38
|
+
#
|
39
|
+
# The available commands are: +help+, +update+, +repl+, +up+,
|
40
|
+
# +start_server+, +init+, +down+, +stop_server+, +downup+, +restart_server+,
|
41
|
+
# +list+, +status+, +version+, +play+, +stop+, +parse+, +instruments+, and
|
42
|
+
# +export+.
|
43
|
+
COMMANDS = %i[
|
44
|
+
help update repl up start_server init down stop_server
|
45
|
+
downup restart_server list status version play stop parse
|
46
|
+
instruments export
|
47
|
+
].freeze
|
48
|
+
|
49
|
+
COMMANDS.each do |command|
|
50
|
+
define_method command do |*args, **opts|
|
51
|
+
block = ->key, val do
|
52
|
+
next unless val
|
53
|
+
args.push "--#{key.to_s.tr ?_, ?-}"
|
54
|
+
args.push val.to_s unless val == true
|
55
|
+
end
|
56
|
+
# executable
|
57
|
+
args.unshift Alda.executable
|
58
|
+
args.map! &:to_s
|
59
|
+
# options
|
60
|
+
Alda.options.each &block
|
61
|
+
# subcommand
|
62
|
+
args.push command.to_s
|
63
|
+
# subcommand options
|
64
|
+
opts.each &block
|
65
|
+
# subprocess
|
66
|
+
IO.popen(args, &:read).tap do
|
67
|
+
raise CommandLineError.new $?, _1 if $?.exitstatus.nonzero?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class << self
|
73
|
+
|
74
|
+
##
|
75
|
+
# The path to the +alda+ executable.
|
76
|
+
#
|
77
|
+
# The default value is <tt>"alda"</tt>,
|
78
|
+
# which will depend on your +PATH+.
|
79
|
+
attr_accessor :executable
|
80
|
+
|
81
|
+
##
|
82
|
+
# The commandline options set using ::[].
|
83
|
+
# Not the subcommand options.
|
84
|
+
# Clear it using ::clear_options.
|
85
|
+
attr_reader :options
|
86
|
+
|
87
|
+
##
|
88
|
+
# :call-seq:
|
89
|
+
# Alda[**opts] -> self
|
90
|
+
#
|
91
|
+
# Sets the options of alda command.
|
92
|
+
# Not the subcommand options.
|
93
|
+
#
|
94
|
+
# Alda[port: 1108].up # => "[1108] ..."
|
95
|
+
# Alda.status # => "[1108] ..."
|
96
|
+
#
|
97
|
+
# Further set options will be merged.
|
98
|
+
# The options can be seen by ::options.
|
99
|
+
# To clear them, use ::clear_options.
|
100
|
+
def [] **opts
|
101
|
+
@options.merge! opts
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
##
|
106
|
+
# :call-seq:
|
107
|
+
# clear_options() -> nil
|
108
|
+
#
|
109
|
+
# Clears the command line options.
|
110
|
+
# Makes ::options an empty Array.
|
111
|
+
def clear_options
|
112
|
+
@options.clear
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
@executable = 'alda'
|
117
|
+
@options = {}
|
118
|
+
|
119
|
+
##
|
120
|
+
# :call-seq:
|
121
|
+
# up?() -> true or false
|
122
|
+
#
|
123
|
+
# Whether the alda server is up.
|
124
|
+
def up?
|
125
|
+
status.include? 'up'
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# :call-seq:
|
130
|
+
# down? -> true or false
|
131
|
+
#
|
132
|
+
# Whether the alda server is down.
|
133
|
+
def down?
|
134
|
+
status.include? 'down'
|
135
|
+
end
|
136
|
+
|
137
|
+
module_function :up?, :down?, *COMMANDS
|
138
|
+
|
139
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
##
|
2
|
+
# The error is raised when +alda+ command exits with nonzero status.
|
3
|
+
class Alda::CommandLineError < StandardError
|
4
|
+
|
5
|
+
##
|
6
|
+
# The <tt>Process::Status</tt> object representing the status of
|
7
|
+
# the process that runs +alda+ command.
|
8
|
+
attr_reader :status
|
9
|
+
|
10
|
+
##
|
11
|
+
# The port on which the problematic alda server runs.
|
12
|
+
#
|
13
|
+
# begin
|
14
|
+
# Alda[port: 1108].play code: 'y'
|
15
|
+
# rescue CommandLineError => e
|
16
|
+
# e.port # => 1108
|
17
|
+
# end
|
18
|
+
attr_reader :port
|
19
|
+
|
20
|
+
##
|
21
|
+
# :call-seq:
|
22
|
+
# new(status, msg=nil) -> Alda::CommandLineError
|
23
|
+
#
|
24
|
+
# Create a Alda::CommandLineError object.
|
25
|
+
# +status+ is the status of the process running +alda+ command.
|
26
|
+
# +msg+ is output of +alda+ command. port# info is extracted from +msg+.
|
27
|
+
def initialize status, msg = nil
|
28
|
+
if match = msg&.match(/^\[(?<port>\d+)\]\sERROR\s(?<message>.*)$/)
|
29
|
+
super match[:message]
|
30
|
+
@port = match[:port].to_i
|
31
|
+
else
|
32
|
+
super msg
|
33
|
+
@port = nil
|
34
|
+
end
|
35
|
+
@status = status
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# This error is raised when one tries to
|
41
|
+
# append events in an Alda::EventList in a wrong order.
|
42
|
+
#
|
43
|
+
# Alda::Score.new do
|
44
|
+
# motif = f4 f e e d d c2
|
45
|
+
# g4 f e d c2 # It commented out, error will not occur
|
46
|
+
# c4 c g g a a g2 motif # (OrderError)
|
47
|
+
# end
|
48
|
+
class Alda::OrderError < StandardError
|
49
|
+
|
50
|
+
##
|
51
|
+
# The expected element gotten if it is of the correct order.
|
52
|
+
#
|
53
|
+
# See #got
|
54
|
+
#
|
55
|
+
# Alda::Score.new do
|
56
|
+
# motif = f4 f e e d d c2
|
57
|
+
# g4 f e d c2
|
58
|
+
# p @events.size # => 2
|
59
|
+
# c4 c g g a a g2 motif
|
60
|
+
# rescue OrderError => e
|
61
|
+
# p @events.size # => 1
|
62
|
+
# p e.expected # => #<Alda::EventContainer:...>
|
63
|
+
# p e.got # => #<Alda::EventContainer:...>
|
64
|
+
# end
|
65
|
+
attr_reader :expected
|
66
|
+
|
67
|
+
##
|
68
|
+
# The actually gotten element.
|
69
|
+
# For an example, see #expected.
|
70
|
+
attr_reader :got
|
71
|
+
|
72
|
+
##
|
73
|
+
# :call-seq:
|
74
|
+
# new(expected, got) -> Alda::OrderError
|
75
|
+
def initialize expected, got
|
76
|
+
super 'events are out of order'
|
77
|
+
@expected = expected
|
78
|
+
@got = got
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,983 @@
|
|
1
|
+
##
|
2
|
+
# The class of elements of Alda::EventList#events.
|
3
|
+
class Alda::Event
|
4
|
+
|
5
|
+
##
|
6
|
+
# The Alda::EventList object that contains it.
|
7
|
+
#
|
8
|
+
# Note that it may not be directly contained, but with an Alda::EventContainer
|
9
|
+
# object in the middle.
|
10
|
+
attr_accessor :parent
|
11
|
+
|
12
|
+
##
|
13
|
+
# The Alda::EventContainer object that contains it.
|
14
|
+
# It may be +nil+ if there is not a container containing it,
|
15
|
+
# especially probably when it itself is an Alda::EventContainer.
|
16
|
+
attr_accessor :container
|
17
|
+
|
18
|
+
##
|
19
|
+
# The callback invoked when it is contained in an Alda::EventContainer.
|
20
|
+
# It is overridden in Alda::InlineLisp and Alda::EventList.
|
21
|
+
# It is called in Alda::EventContainer#on_containing.
|
22
|
+
#
|
23
|
+
# class Alda::Note
|
24
|
+
# def on_contained
|
25
|
+
# super
|
26
|
+
# puts 'a note contained'
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
# Alda::Score.new { c } # => outputs "a note contained"
|
30
|
+
def on_contained
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# :call-seq:
|
35
|
+
# to_alda_code() -> String
|
36
|
+
#
|
37
|
+
# Converts to alda code. To be overridden in subclasses.
|
38
|
+
def to_alda_code
|
39
|
+
''
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Delete itself from its #parent.
|
44
|
+
# If it is not at its #parent's end, raises Alda::OrderError.
|
45
|
+
#
|
46
|
+
# Here is a list of cases where the method is invoked:
|
47
|
+
#
|
48
|
+
# 1. Using the sequence sugar when operating an Alda::EventList.
|
49
|
+
#
|
50
|
+
# 2. Using Alda::EventContainer#/ to create chords or
|
51
|
+
# parts of multiple instruments.
|
52
|
+
#
|
53
|
+
# 3. Using dot accessor of Alda::Part. See Alda::Part#method_missing.
|
54
|
+
#
|
55
|
+
# 4. Using the inline lisp sugar. See Alda::InlineLisp.
|
56
|
+
#
|
57
|
+
# This method needs invoking in these cases because
|
58
|
+
# if an event is created using Alda::EventList sugars
|
59
|
+
# (see Alda::EventList#method_missing), it is automatically
|
60
|
+
# pushed to its #parent.
|
61
|
+
# However, the cases above requires the event be contained
|
62
|
+
# in another object.
|
63
|
+
def detach_from_parent
|
64
|
+
if @parent && self != (got = @parent.events.pop)
|
65
|
+
raise Alda::OrderError.new self, got
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# The class for objects containing an event.
|
72
|
+
#
|
73
|
+
# Alda::EventContainer objects are literally everywhere
|
74
|
+
# if you are a heavy user of event list sugars.
|
75
|
+
# See Alda::EventList#method_missing.
|
76
|
+
class Alda::EventContainer < Alda::Event
|
77
|
+
|
78
|
+
##
|
79
|
+
# The contained Alda::Event object.
|
80
|
+
#
|
81
|
+
# Alda::Score.new do
|
82
|
+
# p c.event.class # => Alda::Note
|
83
|
+
# p((e/g).event.class) # => Alda::Chord
|
84
|
+
# p((a b).event.class) # => Alda::Sequence
|
85
|
+
# end
|
86
|
+
attr_accessor :event
|
87
|
+
|
88
|
+
##
|
89
|
+
# The repetition counts. +nil+ if none.
|
90
|
+
#
|
91
|
+
# Alda::Score.new do
|
92
|
+
# p((c*2).count) # => 2
|
93
|
+
# p((d*3*5).count) # => 15
|
94
|
+
# end
|
95
|
+
attr_accessor :count
|
96
|
+
|
97
|
+
##
|
98
|
+
# The repetition labels. Empty if none.
|
99
|
+
#
|
100
|
+
# Alda::Score.new do
|
101
|
+
# p((c%2).labels) # => [2]
|
102
|
+
# p((c%[2,4..6]).labels) # => [2, 4..6]
|
103
|
+
# end
|
104
|
+
attr_accessor :labels
|
105
|
+
|
106
|
+
##
|
107
|
+
# :call-seq:
|
108
|
+
# new(event, parent) -> Alda::EventContainer
|
109
|
+
#
|
110
|
+
# Creates a new Alda::EventContainer.
|
111
|
+
# Invokes #on_containing.
|
112
|
+
#
|
113
|
+
# +event+ is the Alda::Event object to be contained.
|
114
|
+
#
|
115
|
+
# +parent+ is the Alda::EventList object containing the event.
|
116
|
+
def initialize event, parent
|
117
|
+
@event = event
|
118
|
+
@parent = parent
|
119
|
+
@labels = []
|
120
|
+
on_containing
|
121
|
+
end
|
122
|
+
|
123
|
+
##
|
124
|
+
# :call-seq:
|
125
|
+
# container / other -> container
|
126
|
+
#
|
127
|
+
# Makes #event an Alda::Chord object.
|
128
|
+
#
|
129
|
+
# Alda::Score.new { piano_; c/-e/g }.play
|
130
|
+
# # (plays the chord Cm)
|
131
|
+
#
|
132
|
+
# If the contained event is an Alda::Part object,
|
133
|
+
# makes #event a new Alda::Part object.
|
134
|
+
#
|
135
|
+
# Alda::Score.new { violin_/viola_/cello_; e; f; g}.play
|
136
|
+
# # (plays notes E, F, G with three instruments simultaneously)
|
137
|
+
def / other
|
138
|
+
other.detach_from_parent
|
139
|
+
@event =
|
140
|
+
if @event.is_a? Alda::Part
|
141
|
+
Alda::Part.new @event.names + other.event.names, other.event.arg
|
142
|
+
else
|
143
|
+
Alda::Chord.new @event, other.event
|
144
|
+
end
|
145
|
+
self
|
146
|
+
end
|
147
|
+
|
148
|
+
def to_alda_code
|
149
|
+
result = @event.to_alda_code
|
150
|
+
unless @labels.empty?
|
151
|
+
result.concat ?', @labels.map(&:to_alda_code).join(?,)
|
152
|
+
end
|
153
|
+
result.concat ?*, @count.to_alda_code if @count
|
154
|
+
result
|
155
|
+
end
|
156
|
+
|
157
|
+
##
|
158
|
+
# :call-seq:
|
159
|
+
# container * num -> container
|
160
|
+
#
|
161
|
+
# Marks repetition.
|
162
|
+
#
|
163
|
+
# For examples, see #%.
|
164
|
+
def * num
|
165
|
+
@count = (@count || 1) * num
|
166
|
+
self
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# :call-seq:
|
171
|
+
# container % labels -> container
|
172
|
+
#
|
173
|
+
# Marks alternative endings.
|
174
|
+
#
|
175
|
+
# Alda::Score.new { (b a%1)*2 }.to_s
|
176
|
+
# # => "[b a'1]*2"
|
177
|
+
def % labels
|
178
|
+
labels = [labels] unless labels.is_a? Array
|
179
|
+
@labels.replace labels.to_a
|
180
|
+
self
|
181
|
+
end
|
182
|
+
|
183
|
+
##
|
184
|
+
# :call-seq:
|
185
|
+
# event=(event) -> event
|
186
|
+
#
|
187
|
+
# Sets #event and invokes #on_containing.
|
188
|
+
def event= event
|
189
|
+
@event = event
|
190
|
+
on_containing
|
191
|
+
@event
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# A callback invoked in #event= and ::new.
|
196
|
+
def on_containing
|
197
|
+
if @event
|
198
|
+
@event.container = self
|
199
|
+
@event.parent = @parent
|
200
|
+
@event.on_contained
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
##
|
205
|
+
# :call-seq:
|
206
|
+
# (missing method) -> obj
|
207
|
+
#
|
208
|
+
# Calls method on #event.
|
209
|
+
#
|
210
|
+
# Note that if the method of #event returns #event itself,
|
211
|
+
# the method here returns the container itself.
|
212
|
+
#
|
213
|
+
# Alda::Score.new do
|
214
|
+
# container = c
|
215
|
+
# p container.class # => Alda::EventContainer
|
216
|
+
# p container.respond_to? :pitch # => false
|
217
|
+
# p container.pitch # => "c"
|
218
|
+
# p container.respond_to? :+@ # => false
|
219
|
+
# p((+container).class) # => Alda::EventContainer
|
220
|
+
# p to_s # => "c+"
|
221
|
+
# end
|
222
|
+
def method_missing(...)
|
223
|
+
result = @event.__send__(...)
|
224
|
+
result = self if result == @event
|
225
|
+
result
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
##
|
230
|
+
# An inline lisp event. An Alda::EventContainer containing
|
231
|
+
# an Alda::InlineLisp can be derived using event list
|
232
|
+
# sugar. See Alda::EventList#method_missing.
|
233
|
+
#
|
234
|
+
# Sometimes you need help from Alda::LispIdentifier.
|
235
|
+
#
|
236
|
+
# It serves as attributes in alda codes.
|
237
|
+
#
|
238
|
+
# Alda::Score.new do
|
239
|
+
# tempo! 108
|
240
|
+
# quant! 200
|
241
|
+
# piano_ c e g violin_ g2 e4
|
242
|
+
# end
|
243
|
+
#
|
244
|
+
# Here, <tt>tempo! 108</tt> and <tt>quant! 200</tt>
|
245
|
+
# are inline lisp events and serves for alda attributes.
|
246
|
+
#
|
247
|
+
# It can participate in the sequence sugar if it is
|
248
|
+
# at the end of the sequence.
|
249
|
+
#
|
250
|
+
# Alda::Score.new do
|
251
|
+
# piano_ c d e quant 200
|
252
|
+
# g o! c o? c2
|
253
|
+
# end
|
254
|
+
#
|
255
|
+
# You can operate a score by purely using inline lisp events.
|
256
|
+
#
|
257
|
+
# Alda::Score.new do
|
258
|
+
# part 'piano'
|
259
|
+
# key_sig [:d, :major]
|
260
|
+
# note pitch :d
|
261
|
+
# note pitch :e
|
262
|
+
# note pitch(:f), duration(note_length 2)
|
263
|
+
# end
|
264
|
+
#
|
265
|
+
# When using event list sugar to create inline lisp events,
|
266
|
+
# note that it is not previously defined as a variable.
|
267
|
+
# See Alda::SetVariable and Alda::GetVariable.
|
268
|
+
#
|
269
|
+
# Alda::Score.new do
|
270
|
+
# piano_
|
271
|
+
# p barline.event.class # => Alda::InlineLisp
|
272
|
+
# barline__ c d e f
|
273
|
+
# p barline.event.class # => Alda::GetVariable
|
274
|
+
# end
|
275
|
+
#
|
276
|
+
# Whether it is an Alda::SetVariable, Alda::InlineLisp,
|
277
|
+
# or Alda::GetVariable is intelligently determined.
|
278
|
+
#
|
279
|
+
# Alda::Score.new do
|
280
|
+
# piano_
|
281
|
+
# p((tempo 108).event.class) # => Alda::InlineLisp
|
282
|
+
# p tempo { c d }.event.class # => Alda::SetVariable
|
283
|
+
# p tempo.event.class # => Alda::GetVariable
|
284
|
+
# p((tempo 60).event.class) # => Alda::InlineLisp
|
285
|
+
# p to_s
|
286
|
+
# # => "piano: (tempo 108) tempo = [c d]\n tempo (tempo 60)"
|
287
|
+
# end
|
288
|
+
#
|
289
|
+
# If you want, you can generate lisp codes using ruby.
|
290
|
+
#
|
291
|
+
# Alda::Score.new do
|
292
|
+
# println reduce _into_, {}, [{dog: 'food'}, {cat: 'chow'}]
|
293
|
+
# end.save 'temp.clj'
|
294
|
+
# `clj temp.clj` # => "[[:dog food] [:cat chow]]\n"
|
295
|
+
class Alda::InlineLisp < Alda::Event
|
296
|
+
|
297
|
+
##
|
298
|
+
# The function name of the lisp function
|
299
|
+
attr_accessor :head
|
300
|
+
|
301
|
+
##
|
302
|
+
# The arguments passed to the lisp function.
|
303
|
+
#
|
304
|
+
# Its elements can be any object that responds to
|
305
|
+
# +to_alda_code+ and +detach_from_parent+.
|
306
|
+
attr_accessor :args
|
307
|
+
|
308
|
+
##
|
309
|
+
# :call-seq:
|
310
|
+
# new(head, *args) -> Alda::InlineLisp
|
311
|
+
#
|
312
|
+
# Creates a new Alda::InlineLisp.
|
313
|
+
#
|
314
|
+
# The underlines "_" in +head+ will be converted to hyphens "-".
|
315
|
+
def initialize head, *args
|
316
|
+
@head = head.to_s.gsub ?_, ?-
|
317
|
+
@args = args
|
318
|
+
end
|
319
|
+
|
320
|
+
def to_alda_code
|
321
|
+
"(#{head} #{args.map(&:to_alda_code).join ' '})"
|
322
|
+
end
|
323
|
+
|
324
|
+
def on_contained
|
325
|
+
super
|
326
|
+
@args.detach_from_parent
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
##
|
331
|
+
# A note event. An Alda::EventContainer containing
|
332
|
+
# an Alda::Note can be derived using Alda::EventList sugar.
|
333
|
+
# See Alda::EventList#method_missing.
|
334
|
+
#
|
335
|
+
# There cannot be tildes and dots in (usual) ruby method names,
|
336
|
+
# so use underlines instead.
|
337
|
+
#
|
338
|
+
# The accidentals can be added using #+@, #-@, and #~, or by
|
339
|
+
# using exclamation mark, question mark or underline.
|
340
|
+
#
|
341
|
+
# Alda::Score.new do
|
342
|
+
# key_sig! [:d, :major]
|
343
|
+
# c4_2 d1108ms e2s
|
344
|
+
# f2! # F sharp
|
345
|
+
# g20ms_4? # G flat
|
346
|
+
# a6_ # A natural
|
347
|
+
# c__ # C (slur)
|
348
|
+
# f___ # D natural (slur)
|
349
|
+
# end
|
350
|
+
class Alda::Note < Alda::Event
|
351
|
+
|
352
|
+
##
|
353
|
+
# The string representing the pitch
|
354
|
+
attr_accessor :pitch
|
355
|
+
|
356
|
+
##
|
357
|
+
# The string representing the duration.
|
358
|
+
#
|
359
|
+
# It ends with a tilde "~" if the note slurs.
|
360
|
+
attr_accessor :duration
|
361
|
+
|
362
|
+
##
|
363
|
+
# :call-seq:
|
364
|
+
# new(pitch, duration) -> Alda::Note
|
365
|
+
#
|
366
|
+
# The underlines in +duration+ will be converted to tildes "~".
|
367
|
+
# Exclamation mark and question mark in +duration+
|
368
|
+
# will be interpreted as accidentals in #pitch.
|
369
|
+
#
|
370
|
+
# The number of underlines at the end of +duration+ means:
|
371
|
+
# neither natural nor slur if 0,
|
372
|
+
# natural if 1,
|
373
|
+
# slur if 2,
|
374
|
+
# both natural and slur if 3.
|
375
|
+
def initialize pitch, duration
|
376
|
+
@pitch = pitch.to_s
|
377
|
+
@duration = duration.to_s.tr ?_, ?~
|
378
|
+
case @duration[-1]
|
379
|
+
when ?! # sharp
|
380
|
+
@pitch.concat ?+
|
381
|
+
@duration[-1] = ''
|
382
|
+
when ?? # flat
|
383
|
+
@pitch.concat ?-
|
384
|
+
@duration[-1] = ''
|
385
|
+
end
|
386
|
+
waves = /(?<str>~+)\z/ =~ @duration ? str.size : return
|
387
|
+
@duration[@duration.length - waves..] = ''
|
388
|
+
if waves >= 2
|
389
|
+
waves -= 2
|
390
|
+
@duration.concat ?~
|
391
|
+
end
|
392
|
+
@pitch.concat ?_ * waves
|
393
|
+
end
|
394
|
+
|
395
|
+
##
|
396
|
+
# :call-seq:
|
397
|
+
# +note -> note
|
398
|
+
#
|
399
|
+
# Append a sharp sign after #pitch.
|
400
|
+
#
|
401
|
+
# Alda::Score.new { piano_; +c }.play
|
402
|
+
# # (plays a C sharp note)
|
403
|
+
def +@
|
404
|
+
@pitch.concat ?+
|
405
|
+
self
|
406
|
+
end
|
407
|
+
|
408
|
+
##
|
409
|
+
# :call-seq:
|
410
|
+
# -note -> note
|
411
|
+
#
|
412
|
+
# Append a flat sign after #pitch.
|
413
|
+
#
|
414
|
+
# Alda::Score.new { piano_; -d }.play
|
415
|
+
# # (plays a D flat note)
|
416
|
+
def -@
|
417
|
+
@pitch.concat ?-
|
418
|
+
self
|
419
|
+
end
|
420
|
+
|
421
|
+
##
|
422
|
+
# :call-seq:
|
423
|
+
# ~note -> note
|
424
|
+
#
|
425
|
+
# Append a natural sign after #pitch.
|
426
|
+
#
|
427
|
+
# Alda::Score.new { piano_; key_sig 'f+'; ~f }.play
|
428
|
+
# # (plays an F note)
|
429
|
+
def ~
|
430
|
+
@pitch.concat ?_
|
431
|
+
self
|
432
|
+
end
|
433
|
+
|
434
|
+
def to_alda_code
|
435
|
+
result = @pitch + @duration
|
436
|
+
result.concat ?*, @count.to_alda_code if @count
|
437
|
+
result
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
##
|
442
|
+
# A rest event. An Alda::EventContainer containing an
|
443
|
+
# Alda::Rest can be created using event list sugar.
|
444
|
+
# See Alda::EventList#method_missing.
|
445
|
+
#
|
446
|
+
# When using event list sugar, its duration can be specified
|
447
|
+
# just like that of Alda::Note.
|
448
|
+
#
|
449
|
+
# Alda::Score.new do
|
450
|
+
# piano_ c8 r4 c8 r4 c4
|
451
|
+
# end
|
452
|
+
class Alda::Rest < Alda::Event
|
453
|
+
|
454
|
+
##
|
455
|
+
# The string representing a duration.
|
456
|
+
attr_accessor :duration
|
457
|
+
|
458
|
+
##
|
459
|
+
# :call-seq:
|
460
|
+
# new(duration) -> Alda::Rest
|
461
|
+
#
|
462
|
+
# Creates an Alda::Rest.
|
463
|
+
#
|
464
|
+
# Underlines "_" in +duration+ will be converted to tildes "~".
|
465
|
+
def initialize duration
|
466
|
+
@duration = duration.to_s.tr ?_, ?~
|
467
|
+
end
|
468
|
+
|
469
|
+
def to_alda_code
|
470
|
+
?r + @duration
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
##
|
475
|
+
# An octave event. An Alda::EventContainer containing
|
476
|
+
# an Alda::Octave can be derived using event list sugar.
|
477
|
+
# See Alda::EventList#method_missing.
|
478
|
+
#
|
479
|
+
# +o!+ means octave up, and +o?+ means octave down.
|
480
|
+
# You can also use #+@ and #-@ to denote octave up and down.
|
481
|
+
class Alda::Octave < Alda::Event
|
482
|
+
|
483
|
+
##
|
484
|
+
# The string representing the octave's number.
|
485
|
+
#
|
486
|
+
# It can be empty, in which case
|
487
|
+
# it is purely serving for #+@ and #-@.
|
488
|
+
attr_accessor :num
|
489
|
+
|
490
|
+
##
|
491
|
+
# Positive for up, negative for down, and +0+ as default.
|
492
|
+
#
|
493
|
+
# Alda::Score.new do
|
494
|
+
# p((++++o).event.up_or_down) # => 4
|
495
|
+
# end
|
496
|
+
attr_accessor :up_or_down
|
497
|
+
|
498
|
+
##
|
499
|
+
# :call-seq:
|
500
|
+
# new(num) -> Alda::Octave
|
501
|
+
#
|
502
|
+
# Creates an Alda::Octave.
|
503
|
+
def initialize num
|
504
|
+
@num = num.to_s
|
505
|
+
@up_or_down = 0
|
506
|
+
end
|
507
|
+
|
508
|
+
##
|
509
|
+
# :call-seq:
|
510
|
+
# +octave -> octave
|
511
|
+
#
|
512
|
+
# \Octave up.
|
513
|
+
#
|
514
|
+
# Alda::Score.new { piano_; c; +o; c }.play
|
515
|
+
# # (plays C4, then C5)
|
516
|
+
#
|
517
|
+
# See #-@.
|
518
|
+
def +@
|
519
|
+
@up_or_down += 1
|
520
|
+
self
|
521
|
+
end
|
522
|
+
|
523
|
+
##
|
524
|
+
# :call-seq:
|
525
|
+
# -octave -> octave
|
526
|
+
#
|
527
|
+
# \Octave down.
|
528
|
+
# See #+@.
|
529
|
+
def -@
|
530
|
+
@up_or_down -= 1
|
531
|
+
self
|
532
|
+
end
|
533
|
+
|
534
|
+
def to_alda_code
|
535
|
+
case @up_or_down <=> 0
|
536
|
+
when 0
|
537
|
+
?o + @num
|
538
|
+
when 1
|
539
|
+
?> * @up_or_down
|
540
|
+
when -1
|
541
|
+
?< * -@up_or_down
|
542
|
+
end
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
##
|
547
|
+
# A chord event.
|
548
|
+
# Includes Alda::EventList.
|
549
|
+
#
|
550
|
+
# An Alda::EventContainer containing an Alda::Chord
|
551
|
+
# can be created using event list sugar.
|
552
|
+
# See Alda::EventList#method_missing.
|
553
|
+
#
|
554
|
+
# Alda::Score.new do
|
555
|
+
# p x{ c; e; g }.event.class # => Alda::Chord
|
556
|
+
# end
|
557
|
+
#
|
558
|
+
# The event contained by an Alda::EventContainer
|
559
|
+
# can become an Alda::Chord by using Alda::EventContainer#/.
|
560
|
+
class Alda::Chord < Alda::Event
|
561
|
+
include Alda::EventList
|
562
|
+
|
563
|
+
##
|
564
|
+
# :call-seq:
|
565
|
+
# new(*events, &block) -> Alda::Chord
|
566
|
+
#
|
567
|
+
# There is an event list sugar invoking this method.
|
568
|
+
# See Alda::EventList#method_missing.
|
569
|
+
#
|
570
|
+
# In most cases, +events+ should be empty.
|
571
|
+
# Note that +events+ cannot be specified using the sugar.
|
572
|
+
# +block+ is to be passed with the chord object as +self+.
|
573
|
+
#
|
574
|
+
# Alda::Score.new { piano_; x { c; -e; g } }.play
|
575
|
+
# # (plays chord Cm)
|
576
|
+
def initialize *events, &block
|
577
|
+
@events = events
|
578
|
+
super &block
|
579
|
+
end
|
580
|
+
|
581
|
+
def to_alda_code
|
582
|
+
events_alda_codes ?/
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
586
|
+
##
|
587
|
+
# A part event. An Alda::EventContainer containing an
|
588
|
+
# Alda::Part can be derived using event list sugar.
|
589
|
+
# See Alda::EventList#method_missing.
|
590
|
+
#
|
591
|
+
# A part can have nickname.
|
592
|
+
#
|
593
|
+
# Alda::Score.new do
|
594
|
+
# piano_ 'player1'
|
595
|
+
# c4 d e e e1
|
596
|
+
# piano_ 'player2'
|
597
|
+
# e4 d g g g1
|
598
|
+
# end
|
599
|
+
#
|
600
|
+
# You can use Alda::EventContainer#/ to have a set of
|
601
|
+
# instruments.
|
602
|
+
#
|
603
|
+
# Alda::Score.new do
|
604
|
+
# violin_/viola_
|
605
|
+
# c2 d4 e2_4
|
606
|
+
# end
|
607
|
+
#
|
608
|
+
# A set of instruments can also have nickname.
|
609
|
+
# You can also access an instruments from a set.
|
610
|
+
# See #method_missing.
|
611
|
+
#
|
612
|
+
# Alda::Score.new do
|
613
|
+
# violin_/viola_/cello_('strings')
|
614
|
+
# g1_1_1
|
615
|
+
# strings_.cello_
|
616
|
+
# c1_1_1
|
617
|
+
# end
|
618
|
+
class Alda::Part < Alda::Event
|
619
|
+
|
620
|
+
##
|
621
|
+
# The names of the part. To be joined with +/+ as delimiter.
|
622
|
+
attr_accessor :names
|
623
|
+
|
624
|
+
##
|
625
|
+
# The nickname of the part. +nil+ if none.
|
626
|
+
attr_accessor :arg
|
627
|
+
|
628
|
+
##
|
629
|
+
# :call-seq:
|
630
|
+
# new(names, arg=nil) -> Alda::Part
|
631
|
+
#
|
632
|
+
# Creates an Alda::Part.
|
633
|
+
def initialize names, arg = nil
|
634
|
+
@names = names.map { |name| name.to_s.tr ?_, ?- }
|
635
|
+
@arg = arg
|
636
|
+
end
|
637
|
+
|
638
|
+
def to_alda_code
|
639
|
+
result = @names.join ?/
|
640
|
+
result.concat " \"#{@arg}\"" if @arg
|
641
|
+
result.concat ?:
|
642
|
+
end
|
643
|
+
|
644
|
+
##
|
645
|
+
# :call-seq:
|
646
|
+
# part.(component)_() -> Alda::EventContainer or Alda::Part
|
647
|
+
#
|
648
|
+
# Enables dot accessor.
|
649
|
+
#
|
650
|
+
# Alda::Score.new do
|
651
|
+
# violin_/viola_/cello_('strings'); g1_1_1
|
652
|
+
# strings_.cello_; -o; c1_1_1
|
653
|
+
# end.play
|
654
|
+
def method_missing name, *args
|
655
|
+
str = name.to_s
|
656
|
+
return super unless str[-1] == ?_
|
657
|
+
str[-1] = ''
|
658
|
+
@names.last.concat ?., str
|
659
|
+
if args.size == 1
|
660
|
+
unless @container
|
661
|
+
@container = Alda::EventContainer.new nil, @parent
|
662
|
+
@parent.events.delete self
|
663
|
+
@parent.push @container
|
664
|
+
end
|
665
|
+
@container.event = Alda::Sequence.join self, args.first.tap(&:detach_from_parent)
|
666
|
+
@container
|
667
|
+
else
|
668
|
+
@container || self
|
669
|
+
end
|
670
|
+
end
|
671
|
+
end
|
672
|
+
|
673
|
+
##
|
674
|
+
# A voice event. An Alda::EventContainer containing an
|
675
|
+
# Alda::Voice can be created using event list sugar.
|
676
|
+
# See Alda::EventList#method_missing.
|
677
|
+
#
|
678
|
+
# Alda::Score.new do
|
679
|
+
# piano_ v1 c d e f v2 e f g a
|
680
|
+
# end
|
681
|
+
class Alda::Voice < Alda::Event
|
682
|
+
|
683
|
+
##
|
684
|
+
# The string representing the voice's number.
|
685
|
+
attr_accessor :num
|
686
|
+
|
687
|
+
##
|
688
|
+
# :call-seq:
|
689
|
+
# new(num) -> Alda::Voice
|
690
|
+
#
|
691
|
+
# Creates an Alda::Voice.
|
692
|
+
def initialize num
|
693
|
+
@num = num
|
694
|
+
end
|
695
|
+
|
696
|
+
def to_alda_code
|
697
|
+
?V + num + ?:
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
701
|
+
##
|
702
|
+
# A CRAM event.
|
703
|
+
# Includes Alda::EventList.
|
704
|
+
#
|
705
|
+
# An Alda::EventContainer containing an Alda::Cram
|
706
|
+
# can be created using event list sugar.
|
707
|
+
# See Alda::EventList#method_missing.
|
708
|
+
#
|
709
|
+
# The duration of a cram event can be specified
|
710
|
+
# just like that of an Alda::Note.
|
711
|
+
#
|
712
|
+
# Alda::Score.new do
|
713
|
+
# piano_ c3 t4 { c2 d4 e f }; g2
|
714
|
+
# end
|
715
|
+
class Alda::Cram < Alda::Event
|
716
|
+
include Alda::EventList
|
717
|
+
|
718
|
+
##
|
719
|
+
# The string representing the duration of the CRAM.
|
720
|
+
attr_accessor :duration
|
721
|
+
|
722
|
+
##
|
723
|
+
# There is an event list sugar invoking this method,
|
724
|
+
# see Alda::EventList#method_missing.
|
725
|
+
#
|
726
|
+
# +block+ is to be passed with the CRAM object as +self+.
|
727
|
+
#
|
728
|
+
# Alda::Score.new { piano_; t8 { a; b }}
|
729
|
+
def initialize duration, &block
|
730
|
+
@duration = duration
|
731
|
+
super &block
|
732
|
+
end
|
733
|
+
|
734
|
+
def to_alda_code
|
735
|
+
"{#{events_alda_codes}}#@duration"
|
736
|
+
end
|
737
|
+
end
|
738
|
+
|
739
|
+
##
|
740
|
+
# A marker event. An Alda::EventContainer containing an
|
741
|
+
# Alda::Marker can be created using event list sugar.
|
742
|
+
# See Alda::EventList#method_missing.
|
743
|
+
#
|
744
|
+
# It should be used together with Alda::AtMarker.
|
745
|
+
#
|
746
|
+
# Alda::Score.new do
|
747
|
+
# piano_ v1 c d _here e2 v2 __here c4 d e2
|
748
|
+
# end
|
749
|
+
class Alda::Marker < Alda::Event
|
750
|
+
|
751
|
+
##
|
752
|
+
# The marker's name
|
753
|
+
attr_accessor :name
|
754
|
+
|
755
|
+
##
|
756
|
+
# :call-seq:
|
757
|
+
# new(name) -> Alda::Marker
|
758
|
+
#
|
759
|
+
# Creates an Alda::Marker.
|
760
|
+
#
|
761
|
+
# Underlines in +name+ is converted to hyphens.
|
762
|
+
def initialize name
|
763
|
+
@name = name.to_s.tr ?_, ?-
|
764
|
+
end
|
765
|
+
|
766
|
+
def to_alda_code
|
767
|
+
?% + @name
|
768
|
+
end
|
769
|
+
end
|
770
|
+
|
771
|
+
##
|
772
|
+
# An at-marker event. An Alda::EventContainer containing
|
773
|
+
# an Alda::AtMarker can be created using event list sugar.
|
774
|
+
# See Alda::EventList#method_missing.
|
775
|
+
#
|
776
|
+
# It should be used together with Alda::Marer.
|
777
|
+
# For examples, see Alda::Marker.
|
778
|
+
class Alda::AtMarker < Alda::Event
|
779
|
+
|
780
|
+
##
|
781
|
+
# The corresponding marker's name
|
782
|
+
attr_accessor :name
|
783
|
+
|
784
|
+
##
|
785
|
+
# :call-seq:
|
786
|
+
# new(name) -> Alda::AtMarker
|
787
|
+
#
|
788
|
+
# Creates an Alda::AtMarker.
|
789
|
+
#
|
790
|
+
# Underlines "_" in +name+ is converted to hyphens "-".
|
791
|
+
def initialize name
|
792
|
+
@name = name.to_s.tr ?_, ?-
|
793
|
+
end
|
794
|
+
|
795
|
+
def to_alda_code
|
796
|
+
?@ + @name
|
797
|
+
end
|
798
|
+
end
|
799
|
+
|
800
|
+
##
|
801
|
+
# A sequence event. Includes Alda::EventList.
|
802
|
+
#
|
803
|
+
# An Alda::EventContainer containing
|
804
|
+
# an Alda::Sequence can be created using event list sugar.
|
805
|
+
# See Alda::EventList#method_missing.
|
806
|
+
#
|
807
|
+
# Alda::Score.new do
|
808
|
+
# p s{ c; d; e; f }.event.class # => Alda::Sequence
|
809
|
+
# end
|
810
|
+
#
|
811
|
+
# There is also a special sequence sugar.
|
812
|
+
#
|
813
|
+
# Alda::Score.new do
|
814
|
+
# p((c d e f).event.class) # => Alda::Sequence
|
815
|
+
# end
|
816
|
+
#
|
817
|
+
# The effects of the two examples above are the same.
|
818
|
+
class Alda::Sequence < Alda::Event
|
819
|
+
include Alda::EventList
|
820
|
+
|
821
|
+
##
|
822
|
+
# Using this module can fix a bug of <tt>Array#flatten</tt>.
|
823
|
+
#
|
824
|
+
# def (a = Object.new).method_missing(...)
|
825
|
+
# Object.new
|
826
|
+
# end
|
827
|
+
# [a].flatten rescue $! # => #<TypeError:...>
|
828
|
+
# using Alda::Sequence::RefineFlatten
|
829
|
+
# [a].flatten # => [#<Object:...>]
|
830
|
+
module RefineFlatten
|
831
|
+
refine Array do
|
832
|
+
def flatten
|
833
|
+
each_with_object [] do |element, result|
|
834
|
+
if element.is_a? Array
|
835
|
+
result.push *element.flatten
|
836
|
+
else
|
837
|
+
result.push element
|
838
|
+
end
|
839
|
+
end
|
840
|
+
end
|
841
|
+
end
|
842
|
+
end
|
843
|
+
using RefineFlatten
|
844
|
+
|
845
|
+
def to_alda_code
|
846
|
+
@events.to_alda_code
|
847
|
+
end
|
848
|
+
|
849
|
+
##
|
850
|
+
# :call-seq:
|
851
|
+
# join(*events) -> Alda::Sequence
|
852
|
+
#
|
853
|
+
# Creates an Alda::Sequence object by joining +events+.
|
854
|
+
#
|
855
|
+
# The Alda::EventContainer objects are extracted,
|
856
|
+
# and the Alda::Sequence objects are flattened.
|
857
|
+
def self.join *events
|
858
|
+
new do
|
859
|
+
@events = events.map do |event|
|
860
|
+
while event.is_a?(Alda::EventContainer) && !event.count && event.labels.empty?
|
861
|
+
event = event.event
|
862
|
+
end
|
863
|
+
event.is_a?(Alda::Sequence) ? event.events : event
|
864
|
+
end.flatten
|
865
|
+
end
|
866
|
+
end
|
867
|
+
end
|
868
|
+
|
869
|
+
##
|
870
|
+
# A set-variable event. Includes Alda::EventList.
|
871
|
+
#
|
872
|
+
# An Alda::EventContainer containing an Alda::SetVariable
|
873
|
+
# can be derived using event list sugar.
|
874
|
+
# See Alda::EventList#method_missing.
|
875
|
+
#
|
876
|
+
# There are several equivalent means of setting variable.
|
877
|
+
# Some of them can be ambiguous with Alda::InlineLisp or
|
878
|
+
# Alda::GetVariable, but it is intelligently chosen.
|
879
|
+
#
|
880
|
+
# Alda::Score.new do
|
881
|
+
# p var.event.class # => Alda::InlineLisp
|
882
|
+
# p((var c d e f).event.class) # => Alda::SetVariable
|
883
|
+
# p var { c d e f }.event.class # => Alda::SetVariable
|
884
|
+
# p((var__ c d e f).event.class) # => Alda::SetVariable
|
885
|
+
# p var__ { c d e f }.event.class # => Alda::SetVariable
|
886
|
+
# p((var c d e f).event.class) # => Alda::Sequence
|
887
|
+
# p var.event.class # => Alda::GetVariable
|
888
|
+
# p var(1).event.class # => Alda::InlineLisp
|
889
|
+
# end
|
890
|
+
class Alda::SetVariable < Alda::Event
|
891
|
+
include Alda::EventList
|
892
|
+
|
893
|
+
##
|
894
|
+
# The name of the variable.
|
895
|
+
attr_accessor :name
|
896
|
+
|
897
|
+
##
|
898
|
+
# The events passed to it using arguments instead of a block.
|
899
|
+
attr_reader :original_events
|
900
|
+
|
901
|
+
##
|
902
|
+
# :call-seq:
|
903
|
+
# new(name, *events, &block) -> Alda::SetVariable
|
904
|
+
#
|
905
|
+
# Creates an Alda::SetVariable.
|
906
|
+
def initialize name, *events, &block
|
907
|
+
@name = name.to_sym
|
908
|
+
@original_events = events
|
909
|
+
@events = events.clone
|
910
|
+
super &block
|
911
|
+
end
|
912
|
+
|
913
|
+
##
|
914
|
+
# Specially, the returned value ends with a newline "\\n".
|
915
|
+
def to_alda_code
|
916
|
+
"#@name = #{events_alda_codes}\n"
|
917
|
+
end
|
918
|
+
|
919
|
+
def on_contained
|
920
|
+
super
|
921
|
+
@parent.variables.add @name
|
922
|
+
@original_events.detach_from_parent
|
923
|
+
end
|
924
|
+
end
|
925
|
+
|
926
|
+
##
|
927
|
+
# A get-variable event. An Alda::EventContainer containing
|
928
|
+
# an Alda::GetVariable can be derived using event list sugar.
|
929
|
+
# See Alda::EventList#method_missing.
|
930
|
+
#
|
931
|
+
# This can be ambiguous with Alda::SetVariable and
|
932
|
+
# Alda::InlineLisp. For examples, see Alda::SetVariable.
|
933
|
+
class Alda::GetVariable < Alda::Event
|
934
|
+
|
935
|
+
##
|
936
|
+
# The name of the variable.
|
937
|
+
attr_accessor :name
|
938
|
+
|
939
|
+
##
|
940
|
+
# :call-seq:
|
941
|
+
# new(name) -> Alda::GetVariable
|
942
|
+
#
|
943
|
+
# Creates an Alda::GetVariable.
|
944
|
+
def initialize name
|
945
|
+
@name = name
|
946
|
+
end
|
947
|
+
|
948
|
+
def to_alda_code
|
949
|
+
@name.to_s
|
950
|
+
end
|
951
|
+
end
|
952
|
+
|
953
|
+
##
|
954
|
+
# A lisp identifier event. An Alda::EventContainer containing
|
955
|
+
# an Alda::Lisp
|
956
|
+
#
|
957
|
+
# It is in fact not a kind of event in alda.
|
958
|
+
# However, such a thing is needed when writing some
|
959
|
+
# lisp codes in alda.
|
960
|
+
#
|
961
|
+
# A standalone lisp identifier is useless.
|
962
|
+
# Use it together with Alda::InlineLisp.
|
963
|
+
class Alda::LispIdentifier < Alda::Event
|
964
|
+
|
965
|
+
##
|
966
|
+
# The name of the lisp identifier.
|
967
|
+
attr_accessor :name
|
968
|
+
|
969
|
+
##
|
970
|
+
# :call-seq:
|
971
|
+
# new(name) -> Alda::LispIdentifier
|
972
|
+
#
|
973
|
+
# Creates an Alda::LispIdentifier.
|
974
|
+
#
|
975
|
+
# Underlines "_" in +name+ is converted to hyphens "-".
|
976
|
+
def initialize name
|
977
|
+
@name = name.tr ?_, ?-
|
978
|
+
end
|
979
|
+
|
980
|
+
def to_alda_code
|
981
|
+
@name
|
982
|
+
end
|
983
|
+
end
|