alda-rb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4b8cd5dc1dfccedec4cebe301d7e3cfe95cbf68014b0e5842414577eb08c5b67
4
+ data.tar.gz: f40b5266fbfbb09088737ed7c14010ab47c53a2f17f79c130a55593f0dc3f048
5
+ SHA512:
6
+ metadata.gz: ed6827f9c90c26b0a83706730ba439db7c6263a8196cb4a06b8407338e6e43ce8f2309f5f522ee1326c19c88dd519bec1c3c08eae3be991c984ab9b069378947
7
+ data.tar.gz: 2f1669cf6cfb7712f3ce8736d96b45caa074579a6b10dbaef5478e24cfbf8fed4796c51c09b03de957adee6314c5052a21549c646e222a9c3c4340364abeea9a
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ /.idea/
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.0
6
+ before_install: gem install bundler -v 2.1.2
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at 2938747508@qq.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [https://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: https://contributor-covenant.org
74
+ [version]: https://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in alda-rb-rb.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
7
+ gem "minitest", "~> 5.0"
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Ulysses
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
13
+ all 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
21
+ THE SOFTWARE.
@@ -0,0 +1,66 @@
1
+ # Alda-rb
2
+
3
+ A Ruby library for live-coding music with [Alda](https://alda.io/).
4
+ Also provides a Alda DSL in Ruby.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'alda-rb'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle install
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install alda-rb
21
+
22
+ ## Usage
23
+
24
+ [Install Alda](https://github.com/alda-lang/alda#Installation),
25
+ and try the following Ruby codes yourself:
26
+
27
+ ```ruby
28
+ require 'alda-rb'
29
+
30
+ Alda.up if Alda.down?
31
+ puts Alda.version
32
+
33
+ score = Alda::Score.new { o4; c4/e/g; -d8; r8_16; +f4; o5; c2 }
34
+ Alda::Score.new do
35
+ piano_
36
+ quant 200
37
+ v1
38
+ 5.times do |t|
39
+ transpose t
40
+ import score
41
+ note midi_note(30 + t * t), duration(note_length 1)
42
+ end
43
+ v2; o6
44
+ motif = -> { c200ms; d500ms }
45
+ 8.times { motif * 2; e400ms_4; t4 { a; b; c } }
46
+ end.play
47
+ ```
48
+
49
+ ## Development
50
+
51
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
52
+
53
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
54
+
55
+ ## Contributing
56
+
57
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/alda-rb. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/alda-rb/blob/master/CODE_OF_CONDUCT.md).
58
+
59
+
60
+ ## License
61
+
62
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
63
+
64
+ ## Code of Conduct
65
+
66
+ Everyone interacting in the Alda::Rb project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/alda-rb/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/alda-rb/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "alda-rb"
7
+ spec.version = Alda::VERSION
8
+ spec.authors = ["Ulysses Zhan"]
9
+ spec.email = ["2938747508@qq.com"]
10
+
11
+ spec.summary = %q{A Ruby library for live-coding music with Alda.}
12
+ # spec.description = %q{TODO: Write a longer description or delete this line.}
13
+ spec.homepage = "https://github.com/UlyssesZh/alda-rb"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
16
+
17
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = spec.homepage
21
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "alda-rb/rb"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,544 @@
1
+ require 'alda-rb/version'
2
+
3
+ class Array
4
+ def to_alda_code
5
+ "[#{map(&:to_alda_code).join ' '}]"
6
+ end
7
+ end
8
+ class Hash
9
+ def to_alda_code
10
+ "{#{to_a.flatten.map(&:to_alda_code).join ' '}}"
11
+ end
12
+ end
13
+ class String
14
+ def to_alda_code
15
+ inspect
16
+ end
17
+ end
18
+ class Symbol
19
+ def to_alda_code
20
+ ?: + to_s
21
+ end
22
+ end
23
+ class Numeric
24
+ def to_alda_code
25
+ inspect
26
+ end
27
+ end
28
+ class Proc
29
+ # Runs +self+ for +n+ times.
30
+ def * n
31
+ if !lambda? || arity == 1
32
+ n.times &self
33
+ else
34
+ n.times { self.() }
35
+ end
36
+ end
37
+ end
38
+
39
+ # The module serving as a namespace.
40
+ module Alda
41
+
42
+ # The path to the +alda+ executable.
43
+ #
44
+ # The default value is <tt>"alda"</tt>,
45
+ # which will depend on your PATH.
46
+ singleton_class.attr_accessor :executable
47
+ @executable = 'alda'
48
+
49
+ # The method give Alda# ability to invoke +alda+ at the command line,
50
+ # using +name+ as subcommand and +args+ as arguments.
51
+ #
52
+ # The return value is the string output by the command in STDOUT.
53
+ #
54
+ # If the exit code is nonzero, a CommandLineError# is raised.
55
+ # @example
56
+ # Alda.version
57
+ # # => "Client version: 1.4.0\nServer version: [27713] 1.4.0\n"
58
+ # Alda.parse '-c', 'bassoon: o3 c'
59
+ # # => "{\"chord-mode\":false,\"current-instruments\":...}\n"
60
+ # Alda.sandwich
61
+ # # => Alda::CommandLineError (Expected a command, got sandwich)
62
+ def self.method_missing name, *args
63
+ name = name.to_s.gsub ?_, ?-
64
+ output = IO.popen [executable, name, *args], &:read
65
+ raise CommandLineError.new $?, output if $?.exitstatus.nonzero?
66
+ output
67
+ end
68
+
69
+ # @return Whether the alda server is up.
70
+ def self.up?
71
+ status.include? 'up'
72
+ end
73
+
74
+ # @return Whether the alda server is down.
75
+ def self.down?
76
+ status.include? 'down'
77
+ end
78
+
79
+ # The error raised when one tries to run a non-existing subcommand
80
+ # of +alda+.
81
+ class CommandLineError < Exception
82
+
83
+ # The <tt>Process::Status</tt> object representing the status of
84
+ # the process that runs +alda+ command.
85
+ attr_accessor :status
86
+
87
+ # Create a CommandLineError# object.
88
+ # @param status The status of the process running +alda+ command.
89
+ # @param msg The exception message.
90
+ def initialize status, msg = nil
91
+ super msg
92
+ @status = status
93
+ end
94
+ end
95
+
96
+ # Including this module can make your class have the ability
97
+ # to have a event list.
98
+ # See docs below to get an overview of its functions.
99
+ module EventList
100
+
101
+ # The array containing the events (Event# objects),
102
+ # most of which are EventContainer# objects.
103
+ attr_accessor :events
104
+
105
+ # Make the object have the ability to appending its +events+
106
+ # conveniently.
107
+ #
108
+ # Here is a list of sugar. When the name of a method meets certain
109
+ # condition, the method is regarded as an event appended to +events+.
110
+ #
111
+ # 1. Starting with 2 lowercase letters and
112
+ # ending with underline character: instrument. See Part#.
113
+ #
114
+ # 2. Starting with 2 lowercase letters: inline lisp code.
115
+ # See InlineLisp#.
116
+ #
117
+ # 3. Starting with "t": CRAM. See Cram#.
118
+ #
119
+ # 4. Starting with one of "a", "b", ..., "g": note. See Note#.
120
+ #
121
+ # 5. Starting with "r": rest. See Rest#.
122
+ #
123
+ # 6. Starting with "x": chord. See Chord#.
124
+ #
125
+ # 7. Starting with "o": octave. See Octave#.
126
+ #
127
+ # 8. Starting with "v": voice. See Voice#.
128
+ #
129
+ # 9. Starting with "__" (2 underlines): at marker. See AtMarker#.
130
+ #
131
+ # 10. Starting with "_" (underline): marker. See Marker#.
132
+ #
133
+ # Notes cannot have dots.
134
+ # To tie multiple durations, +_+ is used instead of +~+.
135
+ #
136
+ # All the appended events are contained in a EventContainer# object,
137
+ # which is to be returned.
138
+ #
139
+ # These sugars forms a DSL.
140
+ # @see #initialize.
141
+ # @return an EventContainer# object.
142
+ def method_missing name, *args, &block
143
+ case
144
+ when /^(?<part>[a-z][a-z].*)_$/ =~ name
145
+ Part.new [part], args.first
146
+ when /^[a-z][a-z].*$/ =~ name
147
+ InlineLisp.new name, *args
148
+ when /^t(?<duration>.*)$/ =~ name
149
+ Cram.new duration, &block
150
+ when /^(?<pitch>[a-g])(?<duration>.*)$/ =~ name
151
+ Note.new pitch, duration
152
+ when /^r(?<duration>.*)$/ =~ name
153
+ Rest.new duration
154
+ when /^x$/ =~ name
155
+ Chord.new &block
156
+ when /^o(?<num>\d*)$/ =~ name
157
+ Octave.new num
158
+ when /^v(?<num>\d+)$/ =~ name
159
+ Voice.new num
160
+ when /^__(?<head>.+)$/ =~ name
161
+ AtMarker.new head
162
+ when /^_(?<head>.+)$/ =~ name
163
+ Marker.new head
164
+ else
165
+ super
166
+ end.then do |event|
167
+ EventContainer.new event, self
168
+ end.tap &@events.method(:push)
169
+ end
170
+
171
+ # Append the events of another EventList# object here.
172
+ # This method covers the disadvantage of alda's being unable to
173
+ # import scores from other files.
174
+ def import event_list
175
+ @events += event_list.events
176
+ end
177
+
178
+ # @param block to be passed with the EventList# object as +self+.
179
+ # @example
180
+ # Alda::Score.new do
181
+ # tempo! 108 # inline lisp
182
+ # piano_ # piano part
183
+ # o4 # octave 4
184
+ # c8; d; e; f # notes
185
+ # g4; g; a; f; g; e; f; d; e; c
186
+ # d4_8 # cannot have '~', use '_' instead
187
+ # o3 b8 o4 c2
188
+ # end
189
+ # # => #<Alda::Score:0x... @events=[...]>
190
+ def initialize &block
191
+ @events ||= []
192
+ instance_eval &block if block
193
+ end
194
+
195
+ # Same as #events
196
+ def to_a
197
+ @events
198
+ end
199
+
200
+ # Join the alda codes of #events with a specified delimiter.
201
+ # Returns a string representing the result.
202
+ def events_alda_codes delimiter = ' '
203
+ @events.map(&:to_alda_code).join delimiter
204
+ end
205
+ end
206
+
207
+ # The class mixes in EventList# and provides a method to play.
208
+ class Score
209
+ include EventList
210
+
211
+ # Plays the score.
212
+ # @return the command line output of the +alda+ command.
213
+ # @example
214
+ # Alda::Score.new { piano_; c; d; e }.play
215
+ # # => "[27713] Parsing/evaluating...\n[27713] Playing...\n"
216
+ # # (and plays the sound)
217
+ def play
218
+ Alda.stop
219
+ Alda.play '--code', events_alda_codes
220
+ end
221
+ end
222
+
223
+ # The class of elements of EventList#events.
224
+ class Event
225
+
226
+ # The EventList# object that contains it.
227
+ # Note that it may not be directly contained, but with a EventContainer#
228
+ # object in the middle.
229
+ attr_accessor :parent
230
+
231
+ # The callback invoked when it is contained in a EventContainer#.
232
+ # It is overridden in InlineLisp#, so be aware if you want to
233
+ # override InlineLisp#on_contained.
234
+ # @example
235
+ # class Alda::Note
236
+ # def on_contained
237
+ # puts 'a note contained'
238
+ # end
239
+ # end
240
+ # Alda::Score.new { c } # => outputs "a note contained"
241
+ def on_contained
242
+ end
243
+
244
+ # Converts to alda code. To be overridden.
245
+ def to_alda_code
246
+ ''
247
+ end
248
+ end
249
+
250
+ # The class for objects containing an event.
251
+ class EventContainer < Event
252
+
253
+ # The contained Event# object.
254
+ attr_accessor :event
255
+
256
+ # @param event The Event# object to be contained.
257
+ # @param parent The EventList# object containing the event.
258
+ def initialize event, parent
259
+ @event = event
260
+ @parent = parent
261
+ @event.parent = @parent
262
+ @event.on_contained
263
+ end
264
+
265
+ # Make #event a Chord# object.
266
+ # @example
267
+ # Alda::Score.new { piano_; c/-e/g }.play
268
+ # # (plays the chord Cm)
269
+ #
270
+ # If the contained event is a Part# object,
271
+ # make #event a new Part# object.
272
+ # @example
273
+ # Alda::Score.new { violin_/viola_/cello_; e; f; g}.play
274
+ # # (plays notes E, F, G with three instruments simultaneously)
275
+ def / other
276
+ raise unless other == @parent.events.pop
277
+ @event =
278
+ if @event.is_a? Part
279
+ Part.new @event.names + other.event.names, other.event.arg
280
+ else
281
+ Chord.new @event, other.event
282
+ end
283
+ self
284
+ end
285
+
286
+ def to_alda_code
287
+ @event.to_alda_code
288
+ end
289
+
290
+ def method_missing name, *args
291
+ @event.__send__ name, *args
292
+ end
293
+ end
294
+
295
+ # Inline lisp event.
296
+ class InlineLisp < Event
297
+
298
+ # The function name of the lisp function
299
+ attr_accessor :head
300
+
301
+ # The arguments passed to the lisp function.
302
+ # Its elements can be
303
+ # Array#, Hash#, Numeric#, String#, Symbol#, or InlineLisp#.
304
+ attr_accessor :args
305
+
306
+ # The underlines in +head+ will be converted to hyphens.
307
+ def initialize head, *args
308
+ @head = head.to_s.gsub ?_, ?-
309
+ @args = args
310
+ end
311
+
312
+ def to_alda_code
313
+ "(#{head} #{args.map(&:to_alda_code).join ' '})"
314
+ end
315
+
316
+ def on_contained
317
+ @args.reverse_each do |event|
318
+ raise if event.is_a?(Event) && event != @parent.events.pop
319
+ end
320
+ end
321
+ end
322
+
323
+ # A note event.
324
+ class Note < Event
325
+
326
+ # The string representing the pitch
327
+ attr_accessor :pitch
328
+
329
+ # The string representing the duration.
330
+ # It ends with +~+ if the note slurs.
331
+ attr_accessor :duration
332
+
333
+ # The underlines in +duration+ will be converted to +~+.
334
+ def initialize pitch, duration
335
+ @pitch = pitch.to_s
336
+ @duration = duration.to_s.gsub ?_, ?~
337
+ end
338
+
339
+ # Append a sharp sign after #pitch.
340
+ # @example
341
+ # Alda::Score.new { piano_; +c }.play
342
+ # # (plays a C\# note)
343
+ def +@
344
+ @pitch += ?+
345
+ self
346
+ end
347
+
348
+ # Append a flat sign after #pitch.
349
+ # @example
350
+ # Alda::Score.new { piano_; -d }.play
351
+ # # (plays a Db note)
352
+ def -@
353
+ @pitch += ?-
354
+ self
355
+ end
356
+
357
+ # Append a natural sign after #pitch
358
+ # @example
359
+ # Alda::Score.new { piano_; key_sig 'f+'; ~f }.play
360
+ # # (plays a F note)
361
+ def ~
362
+ @pitch += ?_
363
+ self
364
+ end
365
+
366
+ def to_alda_code
367
+ @pitch + @duration
368
+ end
369
+ end
370
+
371
+ # A rest event.
372
+ class Rest < Event
373
+
374
+ # The string representing a duration.
375
+ attr_accessor :duration
376
+
377
+ # Underlines in +duration+ will be converted to +~+.
378
+ def initialize duration
379
+ @duration = duration.to_s.gsub ?_, ?~
380
+ end
381
+
382
+ def to_alda_code
383
+ ?r + @duration
384
+ end
385
+ end
386
+
387
+ # An octave event.
388
+ class Octave < Event
389
+
390
+ # The string representing the octave's number.
391
+ # It can be empty, serving for #+@ and #-@.
392
+ attr_accessor :num
393
+
394
+ # Positive for up, negative for down, and 0 as default.
395
+ attr_accessor :up_or_down
396
+
397
+ def initialize num
398
+ @num = num.to_s
399
+ @up_or_down = 0
400
+ end
401
+
402
+ # Octave up.
403
+ # @example
404
+ # Alda::Score.new { piano_; c; +o; c }.play
405
+ # # (plays C4, then C5)
406
+ # @see #-@
407
+ def +@
408
+ @up_or_down += 1
409
+ self
410
+ end
411
+
412
+ # Octave down.
413
+ # @see #+@.
414
+ def -@
415
+ @up_or_down -= 1
416
+ self
417
+ end
418
+
419
+ def to_alda_code
420
+ case @up_or_down <=> 0
421
+ when 0
422
+ ?o + @num
423
+ when 1
424
+ ?> * @up_or_down
425
+ when -1
426
+ ?< * -@up_or_down
427
+ end
428
+ end
429
+ end
430
+
431
+ # A chord event.
432
+ # Includes EventList#.
433
+ class Chord < Event
434
+ include EventList
435
+
436
+ # EventList#x invokes this method.
437
+ # @see EventList#method_missing
438
+ # @param events In most cases, should not be used.
439
+ # @param block To be passed with the Chord# object as +self+.
440
+ # @example
441
+ # Alda::Score.new { piano_; x { c; -e; g } }.play
442
+ # # (plays chord Cm)
443
+ def initialize *events, &block
444
+ @events = events
445
+ super &block
446
+ end
447
+
448
+ def to_alda_code
449
+ events_alda_codes ?/
450
+ end
451
+ end
452
+
453
+ # A part event.
454
+ class Part < Event
455
+
456
+ # The names of the part. To be joined with +/+ as delimiter.
457
+ attr_accessor :names
458
+
459
+ # The nickname of the part. +nil+ if none.
460
+ attr_accessor :arg
461
+
462
+ def initialize names, arg = nil
463
+ @names = names.map { |name| name.to_s.gsub ?_, ?- }
464
+ @arg = arg
465
+ end
466
+
467
+ def to_alda_code
468
+ result = @names.join ?/
469
+ result += " \"#{@arg}\"" if @arg
470
+ result + ?:
471
+ end
472
+ end
473
+
474
+ # A voice event.
475
+ class Voice < Event
476
+
477
+ # The string representing the voice's number.
478
+ attr_accessor :num
479
+
480
+ def initialize num
481
+ @num = num
482
+ end
483
+
484
+ def to_alda_code
485
+ ?V + num + ?:
486
+ end
487
+ end
488
+
489
+ # A CRAM event. Includes EventList#.
490
+ class Cram < Event
491
+ include EventList
492
+
493
+ # The string representing the duration of the CRAM.
494
+ attr_accessor :duration
495
+
496
+ # EventList#t invokes this method.
497
+ # @see EventList#method_missing
498
+ # @param block To be passed with the CRAM as +self+.
499
+ # @example
500
+ # Alda::Score.new { piano_; t8 { x; y; }}
501
+ def initialize duration, &block
502
+ @duration = duration
503
+ super &block
504
+ end
505
+
506
+ def to_alda_code
507
+ "{#{events_alda_codes}}#@duration"
508
+ end
509
+ end
510
+
511
+ # A marker event.
512
+ # @see AtMarker#
513
+ class Marker < Event
514
+
515
+ # The marker's name
516
+ attr_accessor :name
517
+
518
+ # Underlines in +name+ is converted to hyphens.
519
+ def initialize name
520
+ @name = name.to_s.gsub ?_, ?-
521
+ end
522
+
523
+ def to_alda_code
524
+ ?% + @name
525
+ end
526
+ end
527
+
528
+ # An at-marker event
529
+ # @see Marker#
530
+ class AtMarker < Event
531
+
532
+ # The corresponding marker's name
533
+ attr_accessor :name
534
+
535
+ # Underlines in +name+ is converted to hyphens.
536
+ def initialize name
537
+ @name = name.to_s.gsub ?_, ?-
538
+ end
539
+
540
+ def to_alda_code
541
+ ?@ + @name
542
+ end
543
+ end
544
+ end
@@ -0,0 +1,3 @@
1
+ module Alda
2
+ VERSION = '0.1.0'
3
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alda-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ulysses Zhan
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-04-15 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - 2938747508@qq.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - ".idea/$CACHE_FILE$"
22
+ - ".idea/alda-rb.iml"
23
+ - ".idea/dictionaries"
24
+ - ".idea/misc.xml"
25
+ - ".idea/modules.xml"
26
+ - ".idea/vcs.xml"
27
+ - ".idea/workspace.xml"
28
+ - ".travis.yml"
29
+ - CODE_OF_CONDUCT.md
30
+ - Gemfile
31
+ - LICENSE.txt
32
+ - README.md
33
+ - Rakefile
34
+ - alda-rb.gemspec
35
+ - bin/console
36
+ - bin/setup
37
+ - lib/alda-rb.rb
38
+ - lib/alda-rb/version.rb
39
+ homepage: https://github.com/UlyssesZh/alda-rb
40
+ licenses:
41
+ - MIT
42
+ metadata:
43
+ homepage_uri: https://github.com/UlyssesZh/alda-rb
44
+ source_code_uri: https://github.com/UlyssesZh/alda-rb
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 2.3.0
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubygems_version: 3.1.2
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: A Ruby library for live-coding music with Alda.
64
+ test_files: []