alda-rb 0.1.2 → 0.1.4
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/Gemfile +1 -1
- data/alda-rb.gemspec +3 -3
- data/examples/alternate_endings.rb +8 -8
- data/examples/bwv846_prelude.rb +13 -11
- data/examples/clapping_music.rb +3 -4
- data/examples/dot_accessor.rb +1 -1
- data/examples/entropy.rb +2 -2
- data/examples/hanon.rb +51 -0
- data/examples/hello_world.rb +1 -2
- data/examples/key_signature.rb +3 -3
- data/examples/midi_note_numbers.rb +1 -1
- data/examples/modes2.rb +1 -1
- data/examples/multi_poly.rb +4 -4
- data/examples/nesting.rb +8 -8
- data/examples/phase.rb +1 -1
- data/examples/seconds_and_milliseconds.rb +1 -1
- data/examples/variables.rb +27 -0
- data/lib/alda-rb.rb +569 -124
- data/lib/alda-rb/version.rb +1 -1
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa068d3caf9d89e4c0bfb90b2bc0800f5fe2824cbd9d3674be7a4853a55e5b25
|
4
|
+
data.tar.gz: ec0c8aa26fd9f789d2bbcaef2502890a21223036779e29704eb8c30ebf08b27f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98860e1ec9598d9935bb59371d8621be062dcab44f524ada4ae1a1a5460f4c85bd440429b38bbdc74032fc19f18cfc0787f575f60593f1e1abceedc5d2ad06c1
|
7
|
+
data.tar.gz: 83a071c40c8e82a5d57a609c668d5f5886d02be45b1656f2a89946208eb590af940e292b550cefbcf4ed930000c1a46b518ec2a204d7f0bca8cb07293911727c
|
data/Gemfile
CHANGED
data/alda-rb.gemspec
CHANGED
@@ -6,19 +6,19 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = "alda-rb"
|
7
7
|
spec.version = Alda::VERSION
|
8
8
|
spec.authors = ["Ulysses Zhan"]
|
9
|
-
spec.email = ["
|
9
|
+
spec.email = ["UlyssesZhan@gmail.com"]
|
10
10
|
|
11
11
|
spec.summary = %q{A Ruby library for live-coding music with Alda.}
|
12
12
|
# spec.description = %q{TODO: Write a longer description or delete this line.}
|
13
13
|
spec.homepage = "https://github.com/UlyssesZh/alda-rb"
|
14
14
|
spec.license = "MIT"
|
15
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
|
16
16
|
|
17
17
|
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
18
18
|
|
19
19
|
spec.metadata["homepage_uri"] = spec.homepage
|
20
20
|
spec.metadata["source_code_uri"] = spec.homepage
|
21
|
-
|
21
|
+
spec.metadata["changelog_uri"] = "https://github.com/UlyssesZh/alda-rb/releases"
|
22
22
|
|
23
23
|
# Specify which files should be added to the gem when it is released.
|
24
24
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
@@ -9,18 +9,18 @@ Alda::Score.new do
|
|
9
9
|
vibraphone_ 'vibes-1'
|
10
10
|
panning 10
|
11
11
|
s do
|
12
|
-
a
|
13
|
-
e4
|
14
|
-
|
15
|
-
|
12
|
+
a b8 o! d o? b g b o! c
|
13
|
+
e4 o? a o! c o? g
|
14
|
+
(g o! g8 f e c o? a4) % (1..2)
|
15
|
+
(b8 o! d g2_4) % 3
|
16
16
|
end * 3
|
17
17
|
|
18
18
|
vibraphone_ 'vibes-2'
|
19
19
|
panning 90
|
20
20
|
s do
|
21
|
-
a
|
22
|
-
b
|
23
|
-
|
24
|
-
|
21
|
+
a o! e o? a r
|
22
|
+
b r b r
|
23
|
+
(g r o! g o? g) % (1..2)
|
24
|
+
(o! d r a g) % 3
|
25
25
|
end * 3
|
26
26
|
end.play
|
data/examples/bwv846_prelude.rb
CHANGED
@@ -10,16 +10,18 @@ require 'alda-rb'
|
|
10
10
|
# sheet music:
|
11
11
|
# http://www.freesheetpianomusic.com/bach/content/Well-Tempered%20Clavier_Book_1/Prelude%20and%20Fugue%20No.1%20C%20major%20BWV%20846.pdf
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
Score.new do
|
16
|
-
def Note.absolute event_list, pitch, duration
|
13
|
+
class Alda::Sequence
|
14
|
+
def absolute pitch, duration
|
17
15
|
/(?<letter>[a-g][-+_]*)(?<octave>\d*)/ =~ pitch
|
18
|
-
octave =
|
19
|
-
|
16
|
+
octave = @@last_octave ||= '4' if octave.empty?
|
17
|
+
result = Alda::Note.new "o#{@@last_octave = octave} #{letter}", duration
|
18
|
+
@events.push result
|
19
|
+
result
|
20
20
|
end
|
21
|
-
|
22
|
-
|
21
|
+
end
|
22
|
+
|
23
|
+
Alda::Score.new do
|
24
|
+
piano_ tempo 60
|
23
25
|
%w[
|
24
26
|
c e g c5 e
|
25
27
|
c4 d a d5 f
|
@@ -55,9 +57,9 @@ Score.new do
|
|
55
57
|
c2 c3 g b- e4
|
56
58
|
].each_slice 5 do |n1, n2, *notes|
|
57
59
|
s do
|
58
|
-
v1
|
59
|
-
v2
|
60
|
-
v3
|
60
|
+
v1 absolute n1, '2'
|
61
|
+
v2 r16 absolute n2, '4..'
|
62
|
+
v3 r8 s{ notes.each { absolute _1, '16' } }*2
|
61
63
|
end * 2
|
62
64
|
end
|
63
65
|
alda_code <<~ENDING
|
data/examples/clapping_music.rb
CHANGED
@@ -12,14 +12,13 @@ require 'alda-rb'
|
|
12
12
|
|
13
13
|
Alda::Score.new do
|
14
14
|
pattern = %i[clap clap clap rest clap clap rest clap rest clap clap rest]
|
15
|
-
pattern.define_singleton_method(:round_shift) { push shift }
|
16
15
|
Alda::Sequence.class_exec do
|
17
16
|
define_method(:clap) { +d }; define_method(:rest) { r }
|
18
17
|
define_method(:play) { pattern.each { __send__ _1 } }
|
19
18
|
end
|
20
19
|
|
21
20
|
tempo! 172
|
22
|
-
midi_percussion_
|
23
|
-
v1; s{ play }*
|
24
|
-
v2; 13.times { s{ play; pattern.
|
21
|
+
midi_percussion_ o2 set_note_length 8
|
22
|
+
v1; s{ play }*12*13
|
23
|
+
v2; 13.times { s{ play; pattern.rotate! }*12 }
|
25
24
|
end.play
|
data/examples/dot_accessor.rb
CHANGED
data/examples/entropy.rb
CHANGED
@@ -13,8 +13,8 @@ Alda::Score.new do
|
|
13
13
|
if rand < REST_RATE
|
14
14
|
pause ms.()
|
15
15
|
octave rand OCTAVE_UPPER
|
16
|
-
note pitch(
|
17
|
-
%i[sharp flat natural]
|
16
|
+
note pitch('abcdefg'[rand 7].to_sym,
|
17
|
+
%i[sharp flat natural].sample), ms.()
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
data/examples/hanon.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'alda-rb'
|
4
|
+
|
5
|
+
SYMBOLS = %i[c d e f g a b]
|
6
|
+
class Solfege
|
7
|
+
attr_accessor :i, :octave
|
8
|
+
def initialize i, octave
|
9
|
+
@i = i
|
10
|
+
@octave = octave
|
11
|
+
update
|
12
|
+
end
|
13
|
+
def update
|
14
|
+
old_octave = @octave
|
15
|
+
@octave, @i = @i.divmod SYMBOLS.size
|
16
|
+
@octave += old_octave
|
17
|
+
end
|
18
|
+
def letter
|
19
|
+
SYMBOLS[@i]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Alda::Sequence
|
24
|
+
def play_solfege solfege
|
25
|
+
v1; octave solfege.octave; note pitch solfege.letter
|
26
|
+
v2; octave solfege.octave-1; note pitch solfege.letter
|
27
|
+
end
|
28
|
+
def play_hanon ary, octave, delta
|
29
|
+
solfeges = ary.map { Solfege.new _1, octave }
|
30
|
+
14.times do
|
31
|
+
solfeges.each do |solfege|
|
32
|
+
play_solfege solfege
|
33
|
+
solfege.i += delta
|
34
|
+
solfege.update
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Alda::Score.new do
|
41
|
+
piano_; set_note_length 16
|
42
|
+
def play_hanon ary1, ary2
|
43
|
+
s do
|
44
|
+
play_hanon ary1, 3, 1
|
45
|
+
play_hanon ary2, 5, -1
|
46
|
+
end * 2
|
47
|
+
end
|
48
|
+
play_hanon [0, 2, 3, 4, 5, 4, 3, 2], [4, 2, 1, 0, -1, 0, 1, 2]
|
49
|
+
play_hanon [0, 2, 5, 4, 3, 4, 3, 2], [4, 1, -1, 0, 1, 0, 1, 2]
|
50
|
+
v1; o3; c2; v2; o2; c2
|
51
|
+
end.play
|
data/examples/hello_world.rb
CHANGED
data/examples/key_signature.rb
CHANGED
@@ -7,11 +7,11 @@ Alda::Score.new do
|
|
7
7
|
quant 200
|
8
8
|
|
9
9
|
key_signature 'f+ c+ g+'
|
10
|
-
a8
|
11
|
-
a
|
10
|
+
a8 b o! c d e f g a o?
|
11
|
+
a b o! c_ d e f_ g_ a o?
|
12
12
|
|
13
13
|
key_signature [:g, :minor]
|
14
|
-
g
|
14
|
+
g a b o! c! d e f! g o?
|
15
15
|
|
16
16
|
key_signature e: [:flat], b: [:flat]
|
17
17
|
g1_1/b/d
|
data/examples/modes2.rb
CHANGED
data/examples/multi_poly.rb
CHANGED
@@ -3,12 +3,12 @@
|
|
3
3
|
require 'alda-rb'
|
4
4
|
|
5
5
|
Alda::Score.new do
|
6
|
-
piano_
|
7
|
-
harp_
|
6
|
+
piano_ set_duration 4
|
7
|
+
harp_ set_duration 2; octave 3
|
8
8
|
|
9
9
|
piano_/harp_
|
10
|
-
t
|
10
|
+
t{ e f g }; t{ a b o! c }
|
11
11
|
|
12
12
|
harp_
|
13
|
-
t
|
13
|
+
t{ d e f }; t { g a b }
|
14
14
|
end.play
|
data/examples/nesting.rb
CHANGED
@@ -6,21 +6,21 @@ Alda::Score.new do
|
|
6
6
|
piano_
|
7
7
|
|
8
8
|
v1
|
9
|
-
c8
|
9
|
+
c8 d e f g2_
|
10
10
|
|
11
11
|
v2
|
12
|
-
|
13
|
-
f
|
12
|
+
(c8 d)*2; e
|
13
|
+
f g*3
|
14
14
|
t do
|
15
|
-
t{ c
|
15
|
+
t{ c c }
|
16
16
|
s{ g/e/c; s{ d }*2 }
|
17
|
-
|
17
|
+
(c d)*5
|
18
18
|
end * 5
|
19
|
-
a/b/c; b
|
19
|
+
a/b/c; b c/e
|
20
20
|
|
21
21
|
v3
|
22
|
-
a8
|
22
|
+
a8 b o! c2_
|
23
23
|
|
24
24
|
clarinet_
|
25
|
-
a2
|
25
|
+
a2 e
|
26
26
|
end.play
|
data/examples/phase.rb
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'alda-rb'
|
4
|
+
|
5
|
+
Alda::Score.new do
|
6
|
+
tempo! 160
|
7
|
+
|
8
|
+
riffA__ f8 f g! a o! c c d c o?
|
9
|
+
riffB__ b8? b? o! c! d f f g f o?
|
10
|
+
riffC__ o! c8 c d! e g g a g o?
|
11
|
+
riffD do
|
12
|
+
f8 f g! a o! c c d o? b o!
|
13
|
+
c c o? b? b? a a g g
|
14
|
+
end
|
15
|
+
|
16
|
+
rockinRiff do
|
17
|
+
riffA*4
|
18
|
+
riffB*2; riffA*2
|
19
|
+
riffC riffB riffD
|
20
|
+
end
|
21
|
+
|
22
|
+
electric_guitar_distorted_ 'guitar'; o2
|
23
|
+
tenor_saxophone_ 'sax'; o3
|
24
|
+
|
25
|
+
guitar_/sax_
|
26
|
+
rockinRiff*8
|
27
|
+
end.play
|
data/lib/alda-rb.rb
CHANGED
@@ -1,35 +1,22 @@
|
|
1
|
+
require 'readline'
|
2
|
+
require 'set'
|
3
|
+
require 'stringio'
|
4
|
+
require 'irb/ruby-lex'
|
1
5
|
require 'alda-rb/version'
|
6
|
+
require 'colorize'
|
7
|
+
|
8
|
+
{
|
9
|
+
Array => -> { "[#{map(&:to_alda_code).join ' '}]" },
|
10
|
+
Hash => -> { "{#{to_a.reduce(:+).map(&:to_alda_code).join ' '}}" },
|
11
|
+
String => -> { dump },
|
12
|
+
Symbol => -> { ?: + to_s },
|
13
|
+
Numeric => -> { inspect },
|
14
|
+
Range => -> { "#{first}-#{last}" },
|
15
|
+
TrueClass => -> { 'true' },
|
16
|
+
FalseClass => -> { 'false' },
|
17
|
+
NilClass => -> { 'nil' }
|
18
|
+
}.each { |klass, block| klass.define_method :to_alda_code, &block }
|
2
19
|
|
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.reduce(:+).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 Range
|
29
|
-
def to_alda_code
|
30
|
-
"#{first}-#{last}"
|
31
|
-
end
|
32
|
-
end
|
33
20
|
class Proc
|
34
21
|
# Runs +self+ for +n+ times.
|
35
22
|
def * n
|
@@ -41,19 +28,35 @@ class Proc
|
|
41
28
|
end
|
42
29
|
end
|
43
30
|
|
31
|
+
class StringIO
|
32
|
+
# Equivalent to #string.
|
33
|
+
def to_s
|
34
|
+
string
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Kernel
|
39
|
+
# Runs the alda command.
|
40
|
+
# Does not capture output.
|
41
|
+
# @example
|
42
|
+
# alda 'version'
|
43
|
+
# alda 'play', '-c', 'piano: a'
|
44
|
+
# alda 'repl'
|
45
|
+
def alda *args
|
46
|
+
system Alda.executable, *args
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
44
50
|
# The module serving as a namespace.
|
45
51
|
module Alda
|
46
52
|
|
47
|
-
# The
|
53
|
+
# The array of available subcommands of alda executable.
|
48
54
|
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
# The method give Alda# ability to invoke +alda+ at the command line,
|
55
|
-
# using +name+ as subcommand and +args+ as arguments.
|
56
|
-
# +opts+ are converted to command line options.
|
55
|
+
# Alda# is able to invoke +alda+ at the command line.
|
56
|
+
# The subcommand is the name of the method invoked upon Alda#.
|
57
|
+
#
|
58
|
+
# The first argument (a hash) is interpreted as the options.
|
59
|
+
# The keyword arguments are interpreted as the subcommand options.
|
57
60
|
#
|
58
61
|
# The return value is the string output by the command in STDOUT.
|
59
62
|
#
|
@@ -63,43 +66,72 @@ module Alda
|
|
63
66
|
# # => "Client version: 1.4.0\nServer version: [27713] 1.4.0\n"
|
64
67
|
# Alda.parse code: 'bassoon: o3 c'
|
65
68
|
# # => "{\"chord-mode\":false,\"current-instruments\":...}\n"
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
69
|
+
COMMANDS = %i[
|
70
|
+
help update repl up start_server init down stop_server
|
71
|
+
downup restart_server list status version play stop parse
|
72
|
+
instruments export
|
73
|
+
].freeze
|
74
|
+
|
75
|
+
COMMANDS.each do |command|
|
76
|
+
define_method command do |*args, **opts|
|
77
|
+
block = ->key, val do
|
78
|
+
next unless val
|
79
|
+
args.push "--#{key.to_s.tr ?_, ?-}"
|
80
|
+
args.push val.to_s unless val == true
|
81
|
+
end
|
82
|
+
# executable
|
83
|
+
args.unshift Alda.executable
|
84
|
+
args.map! &:to_s
|
85
|
+
# options
|
86
|
+
Alda.options.each &block
|
87
|
+
# subcommand
|
88
|
+
args.push command.to_s
|
89
|
+
# subcommand options
|
90
|
+
opts.each &block
|
91
|
+
# subprocess
|
92
|
+
IO.popen(args, &:read).tap do
|
93
|
+
raise CommandLineError.new $?, _1 if $?.exitstatus.nonzero?
|
94
|
+
end
|
95
|
+
end
|
76
96
|
end
|
77
97
|
|
98
|
+
# The path to the +alda+ executable.
|
99
|
+
#
|
100
|
+
# The default value is <tt>"alda"</tt>,
|
101
|
+
# which will depend on your PATH.
|
102
|
+
singleton_class.attr_accessor :executable
|
103
|
+
@executable = 'alda'
|
104
|
+
|
105
|
+
singleton_class.attr_reader :options
|
106
|
+
@options = {}
|
107
|
+
|
78
108
|
# @return Whether the alda server is up.
|
79
|
-
def
|
109
|
+
def up?
|
80
110
|
status.include? 'up'
|
81
111
|
end
|
82
112
|
|
83
113
|
# @return Whether the alda server is down.
|
84
|
-
def
|
114
|
+
def down?
|
85
115
|
status.include? 'down'
|
86
116
|
end
|
87
117
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
118
|
+
module_function :up?, :down?, *COMMANDS
|
119
|
+
|
120
|
+
# Start a REPL session.
|
121
|
+
def self.repl
|
122
|
+
REPL.new.run
|
123
|
+
end
|
124
|
+
|
125
|
+
# Sets the options of alda command.
|
126
|
+
# Not the subcommand options.
|
127
|
+
def self.[] **opts
|
128
|
+
@options.merge! opts
|
129
|
+
self
|
130
|
+
end
|
131
|
+
|
132
|
+
# Clears the command line options.
|
133
|
+
def self.clear_options
|
134
|
+
@options.clear
|
103
135
|
end
|
104
136
|
|
105
137
|
# Including this module can make your class have the ability
|
@@ -111,35 +143,46 @@ module Alda
|
|
111
143
|
# most of which are EventContainer# objects.
|
112
144
|
attr_accessor :events
|
113
145
|
|
146
|
+
# The set containing the available variable names.
|
147
|
+
attr_accessor :variables
|
148
|
+
|
149
|
+
def on_contained
|
150
|
+
instance_eval &@block if @block
|
151
|
+
end
|
152
|
+
|
114
153
|
# Make the object have the ability to appending its +events+
|
115
154
|
# conveniently.
|
116
155
|
#
|
117
156
|
# Here is a list of sugar. When the name of a method meets certain
|
118
157
|
# condition, the method is regarded as an event appended to +events+.
|
119
158
|
#
|
120
|
-
# 1.
|
159
|
+
# 1. Ending with 2 underlines: set variable. See SetVariable#.
|
160
|
+
#
|
161
|
+
# 2. Starting with 2 lowercase letters and
|
121
162
|
# ending with underline character: instrument. See Part#.
|
122
163
|
#
|
123
|
-
#
|
124
|
-
#
|
164
|
+
# 3. Starting with 2 lowercase letters: inline lisp code,
|
165
|
+
# set variable, or get variable.
|
166
|
+
# One of the above three is chosen intelligently.
|
167
|
+
# See InlineLisp#, SetVariable#, GetVariable#.
|
125
168
|
#
|
126
|
-
#
|
169
|
+
# 4. Starting with "t": CRAM. See Cram#.
|
127
170
|
#
|
128
|
-
#
|
171
|
+
# 5. Starting with one of "a", "b", ..., "g": note. See Note#.
|
129
172
|
#
|
130
|
-
#
|
173
|
+
# 6. Starting with "r": rest. See Rest#.
|
131
174
|
#
|
132
|
-
#
|
175
|
+
# 7. "x": chord. See Chord#.
|
133
176
|
#
|
134
|
-
#
|
177
|
+
# 8. "s": sequence. See Sequence#.
|
135
178
|
#
|
136
|
-
#
|
179
|
+
# 9. Starting with "o": octave. See Octave#.
|
137
180
|
#
|
138
|
-
#
|
181
|
+
# 10. Starting with "v": voice. See Voice#.
|
139
182
|
#
|
140
|
-
#
|
183
|
+
# 11. Starting with "__" (2 underlines): at marker. See AtMarker#.
|
141
184
|
#
|
142
|
-
#
|
185
|
+
# 12. Starting with "_" (underline): marker. See Marker#.
|
143
186
|
#
|
144
187
|
# Notes cannot have dots.
|
145
188
|
# To tie multiple durations, +_+ is used instead of +~+.
|
@@ -151,29 +194,59 @@ module Alda
|
|
151
194
|
# @see #initialize.
|
152
195
|
# @return an EventContainer# object.
|
153
196
|
def method_missing name, *args, &block
|
197
|
+
if @parent&.respond_to? name, true
|
198
|
+
return @parent.__send__ name, *args, &block
|
199
|
+
end
|
200
|
+
sequence_sugar = ->event do
|
201
|
+
if args.size == 1
|
202
|
+
joined = args.first
|
203
|
+
unless (got = @events.pop) == (expected = joined)
|
204
|
+
raise OrderError.new expected, got
|
205
|
+
end
|
206
|
+
Sequence.join event, joined
|
207
|
+
else
|
208
|
+
event
|
209
|
+
end
|
210
|
+
end
|
154
211
|
case
|
155
|
-
when
|
156
|
-
|
157
|
-
when
|
158
|
-
|
159
|
-
|
212
|
+
when /\A(?<head>[a-z][a-z].*)__\z/ =~ name
|
213
|
+
SetVariable.new head, *args, &block
|
214
|
+
when /\A(?<part>[a-z][a-z].*)_\z/ =~ name
|
215
|
+
if args.first.is_a? String
|
216
|
+
Part.new [part], args.first
|
217
|
+
else
|
218
|
+
sequence_sugar.(Part.new [part])
|
219
|
+
end
|
220
|
+
when /\A[a-z][a-z].*\z/ =~ name
|
221
|
+
if block
|
222
|
+
SetVariable.new name, *args, &block
|
223
|
+
elsif has_variable?(name) && (args.empty? || args.size == 1 && args.first.is_a?(Event))
|
224
|
+
sequence_sugar.(GetVariable.new name)
|
225
|
+
else
|
226
|
+
InlineLisp.new name, *args
|
227
|
+
end
|
228
|
+
when /\At(?<duration>.*)\z/ =~ name
|
160
229
|
Cram.new duration, &block
|
161
|
-
when
|
162
|
-
Note.new pitch, duration
|
163
|
-
when
|
164
|
-
Rest.new duration
|
165
|
-
when
|
230
|
+
when /\A(?<pitch>[a-g])(?<duration>.*)\z/ =~ name
|
231
|
+
sequence_sugar.(Note.new pitch, duration)
|
232
|
+
when /\Ar(?<duration>.*)\z/ =~ name
|
233
|
+
sequence_sugar.(Rest.new duration)
|
234
|
+
when /\Ax\z/ =~ name
|
166
235
|
Chord.new &block
|
167
|
-
when
|
236
|
+
when /\As\z/ =~ name
|
168
237
|
Sequence.new *args, &block
|
169
|
-
when
|
170
|
-
Octave.new
|
171
|
-
when
|
172
|
-
|
173
|
-
when
|
174
|
-
|
175
|
-
when
|
176
|
-
|
238
|
+
when /\Ao!\z/ =~ name
|
239
|
+
sequence_sugar.(Octave.new('').tap { _1.up_or_down = 1})
|
240
|
+
when /\Ao\?\z/ =~ name
|
241
|
+
sequence_sugar.(Octave.new('').tap { _1.up_or_down = -1})
|
242
|
+
when /\Ao(?<num>\d*)\z/ =~ name
|
243
|
+
sequence_sugar.(Octave.new num)
|
244
|
+
when /\Av(?<num>\d+)\z/ =~ name
|
245
|
+
sequence_sugar.(Voice.new num)
|
246
|
+
when /\A__(?<head>.+)\z/ =~ name
|
247
|
+
sequence_sugar.(AtMarker.new head)
|
248
|
+
when /\A_(?<head>.+)\z/ =~ name
|
249
|
+
sequence_sugar.(Marker.new head)
|
177
250
|
else
|
178
251
|
super
|
179
252
|
end.then do |event|
|
@@ -181,6 +254,10 @@ module Alda
|
|
181
254
|
end.tap &@events.method(:push)
|
182
255
|
end
|
183
256
|
|
257
|
+
def has_variable? name
|
258
|
+
@variables.include?(name) || !!@parent&.has_variable?(name)
|
259
|
+
end
|
260
|
+
|
184
261
|
# Append the events of another EventList# object here.
|
185
262
|
# This method covers the disadvantage of alda's being unable to
|
186
263
|
# import scores from other files.
|
@@ -192,18 +269,19 @@ module Alda
|
|
192
269
|
# @param block to be passed with the EventList# object as +self+.
|
193
270
|
# @example
|
194
271
|
# Alda::Score.new do
|
195
|
-
# tempo! 108
|
196
|
-
# piano_
|
197
|
-
# o4
|
198
|
-
# c8; d; e; f
|
199
|
-
# g4
|
200
|
-
# d4_8
|
201
|
-
# o3 b8 o4 c2
|
272
|
+
# tempo! 108 # inline lisp
|
273
|
+
# piano_ # piano part
|
274
|
+
# o4 # octave 4
|
275
|
+
# c8; d; e; f # notes
|
276
|
+
# g4 g a f g e f d e c # a sequence
|
277
|
+
# d4_8 # cannot have '~', use '_' instead
|
278
|
+
# o3 b8 o4 c2 # a sequence
|
202
279
|
# end
|
203
280
|
# # => #<Alda::Score:0x... @events=[...]>
|
204
281
|
def initialize &block
|
205
282
|
@events ||= []
|
206
|
-
|
283
|
+
@variables ||= Set.new
|
284
|
+
@block ||= block
|
207
285
|
end
|
208
286
|
|
209
287
|
# Same as #events
|
@@ -231,7 +309,6 @@ module Alda
|
|
231
309
|
# Alda::Score.new { piano_; c; d; e }.play from: 1
|
232
310
|
# # (plays only an E note)
|
233
311
|
def play **opts
|
234
|
-
Alda.stop
|
235
312
|
Alda.play code: self, **opts
|
236
313
|
end
|
237
314
|
|
@@ -253,9 +330,231 @@ module Alda
|
|
253
330
|
Alda.export code: self, **opts
|
254
331
|
end
|
255
332
|
|
333
|
+
# Saves the alda codes into a file.
|
334
|
+
def save filename
|
335
|
+
File.open(filename, 'w') { _1.puts to_s }
|
336
|
+
end
|
337
|
+
|
338
|
+
# Loads alda codes from a file.
|
339
|
+
def load filename
|
340
|
+
event = InlineLisp.new :alda_code, File.read(filename)
|
341
|
+
@events.push event
|
342
|
+
event
|
343
|
+
end
|
344
|
+
|
345
|
+
# @return Alda codes.
|
256
346
|
def to_s
|
257
347
|
events_alda_codes
|
258
348
|
end
|
349
|
+
|
350
|
+
# The initialization.
|
351
|
+
def initialize(...)
|
352
|
+
super
|
353
|
+
on_contained
|
354
|
+
end
|
355
|
+
|
356
|
+
# Clears all the events and variables.
|
357
|
+
def clear
|
358
|
+
@events.clear
|
359
|
+
@variables.clear
|
360
|
+
self
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
# An encapsulation for the REPL session for alda-rb.
|
365
|
+
class REPL
|
366
|
+
|
367
|
+
# The score object used in REPL.
|
368
|
+
# Includes Alda#, so it can refer to alda commandline.
|
369
|
+
class TempScore < Score
|
370
|
+
include Alda
|
371
|
+
|
372
|
+
Score.instance_methods(false).each do |meth|
|
373
|
+
define_method meth, Score.instance_method(meth)
|
374
|
+
end
|
375
|
+
|
376
|
+
def initialize session
|
377
|
+
super()
|
378
|
+
@session = session
|
379
|
+
end
|
380
|
+
|
381
|
+
def to_s
|
382
|
+
history
|
383
|
+
end
|
384
|
+
|
385
|
+
def history
|
386
|
+
@session.history.to_s
|
387
|
+
end
|
388
|
+
|
389
|
+
def clear_history
|
390
|
+
@session.clear_history
|
391
|
+
end
|
392
|
+
|
393
|
+
def get_binding
|
394
|
+
binding
|
395
|
+
end
|
396
|
+
|
397
|
+
alias quit exit
|
398
|
+
end
|
399
|
+
|
400
|
+
# The history.
|
401
|
+
attr_reader :history
|
402
|
+
|
403
|
+
# Initialization.
|
404
|
+
def initialize
|
405
|
+
@score = TempScore.new self
|
406
|
+
@binding = @score.get_binding
|
407
|
+
@lex = RubyLex.new
|
408
|
+
@history = StringIO.new
|
409
|
+
end
|
410
|
+
|
411
|
+
# Runs the session. Includes the start, the main loop, and the termination.
|
412
|
+
def run
|
413
|
+
start
|
414
|
+
while code = rb_code
|
415
|
+
break unless process_rb_code code
|
416
|
+
end
|
417
|
+
terminate
|
418
|
+
end
|
419
|
+
|
420
|
+
# Starts the session.
|
421
|
+
def start
|
422
|
+
end
|
423
|
+
|
424
|
+
# Reads the next Ruby codes input in the REPL session.
|
425
|
+
# It can intelligently continue reading if the code is not complete yet.
|
426
|
+
def rb_code
|
427
|
+
result = ''
|
428
|
+
begin
|
429
|
+
buf = Readline.readline '> '.green, true
|
430
|
+
return unless buf
|
431
|
+
result.concat buf, ?\n
|
432
|
+
ltype, indent, continue, block_open = @lex.check_state result
|
433
|
+
rescue Interrupt
|
434
|
+
$stdout.puts
|
435
|
+
retry
|
436
|
+
end while ltype || indent.nonzero? || continue || block_open
|
437
|
+
result
|
438
|
+
end
|
439
|
+
|
440
|
+
# Processes the Ruby codes read.
|
441
|
+
# Sending it to a score and sending the result to alda.
|
442
|
+
# @return +true+ for continue looping, +false+ for breaking the loop.
|
443
|
+
def process_rb_code code
|
444
|
+
@score.clear
|
445
|
+
begin
|
446
|
+
@binding.eval code
|
447
|
+
rescue StandardError, ScriptError => e
|
448
|
+
$stderr.print e.full_message
|
449
|
+
return true
|
450
|
+
rescue Interrupt
|
451
|
+
return true
|
452
|
+
rescue SystemExit
|
453
|
+
return false
|
454
|
+
end
|
455
|
+
code = @score.events_alda_codes
|
456
|
+
unless code.empty?
|
457
|
+
$stdout.puts code.yellow
|
458
|
+
play_score code
|
459
|
+
end
|
460
|
+
true
|
461
|
+
end
|
462
|
+
|
463
|
+
# Tries to run the block and rescue CommandLineError#.
|
464
|
+
def try_command # :block:
|
465
|
+
begin
|
466
|
+
yield
|
467
|
+
rescue CommandLineError => e
|
468
|
+
puts e.message.red
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
# Plays the score.
|
473
|
+
def play_score code
|
474
|
+
try_command do
|
475
|
+
Alda.play code: code, history: @history
|
476
|
+
@history.puts code
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
# Terminates the REPL session.
|
481
|
+
def terminate
|
482
|
+
clear_history
|
483
|
+
end
|
484
|
+
|
485
|
+
# Clears the history.
|
486
|
+
def clear_history
|
487
|
+
@history = StringIO.new
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
# The error is raised when one tries to
|
492
|
+
# run a non-existing subcommand of +alda+.
|
493
|
+
class CommandLineError < StandardError
|
494
|
+
|
495
|
+
# The <tt>Process::Status</tt> object representing the status of
|
496
|
+
# the process that runs +alda+ command.
|
497
|
+
attr_reader :status
|
498
|
+
|
499
|
+
# The port on which the problematic Alda server runs.
|
500
|
+
# @example
|
501
|
+
# begin
|
502
|
+
# Alda.play({port: 1108}, code: "y")
|
503
|
+
# rescue CommandLineError => e
|
504
|
+
# e.port # => 1108
|
505
|
+
# end
|
506
|
+
attr_reader :port
|
507
|
+
|
508
|
+
# Create a CommandLineError# object.
|
509
|
+
# @param status The status of the process running +alda+ command.
|
510
|
+
# @param msg The exception message.
|
511
|
+
def initialize status, msg = nil
|
512
|
+
if match = msg&.match(/^\[(?<port>\d+)\]\sERROR\s(?<message>.*)$/)
|
513
|
+
super match[:message]
|
514
|
+
@port = match[:port].to_i
|
515
|
+
else
|
516
|
+
super msg
|
517
|
+
@port = nil
|
518
|
+
end
|
519
|
+
@status = status
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
# This error is raised when one tries to
|
524
|
+
# append events in an EventList# in a wrong order.
|
525
|
+
# @example
|
526
|
+
# Alda::Score.new do
|
527
|
+
# motif = f4 f e e d d c2
|
528
|
+
# g4 f e d c2 # It commented out, error will not occur
|
529
|
+
# c4 c g g a a g2 motif # (OrderError)
|
530
|
+
# end
|
531
|
+
class OrderError < StandardError
|
532
|
+
|
533
|
+
# The expected element gotten if it is of the correct order.
|
534
|
+
# @see #got
|
535
|
+
# @example
|
536
|
+
# Alda::Score.new do
|
537
|
+
# motif = f4 f e e d d c2
|
538
|
+
# g4 f e d c2
|
539
|
+
# p @events.size # => 2
|
540
|
+
# c4 c g g a a g2 motif
|
541
|
+
# rescue OrderError => e
|
542
|
+
# p @events.size # => 1
|
543
|
+
# p e.expected # => #<Alda::EventContainer:...>
|
544
|
+
# p e.got # => #<Alda::EventContainer:...>
|
545
|
+
# end
|
546
|
+
attr_reader :expected
|
547
|
+
|
548
|
+
# The actually gotten element.
|
549
|
+
# For an example, see #expected.
|
550
|
+
# @see #expected
|
551
|
+
attr_reader :got
|
552
|
+
|
553
|
+
def initialize expected, got
|
554
|
+
super 'events are out of order'
|
555
|
+
@expected = expected
|
556
|
+
@got = got
|
557
|
+
end
|
259
558
|
end
|
260
559
|
|
261
560
|
# The class of elements of EventList#events.
|
@@ -266,9 +565,13 @@ module Alda
|
|
266
565
|
# object in the middle.
|
267
566
|
attr_accessor :parent
|
268
567
|
|
568
|
+
# The EventContainer# object that contains it.
|
569
|
+
# It may be +nil+, especially probably when
|
570
|
+
# it itself is an EventContainer#.
|
571
|
+
attr_accessor :container
|
572
|
+
|
269
573
|
# The callback invoked when it is contained in an EventContainer#.
|
270
|
-
# It is overridden in InlineLisp
|
271
|
-
# override InlineLisp#on_contained.
|
574
|
+
# It is overridden in InlineLisp# and EventList#.
|
272
575
|
# @example
|
273
576
|
# class Alda::Note
|
274
577
|
# def on_contained
|
@@ -302,9 +605,8 @@ module Alda
|
|
302
605
|
def initialize event, parent
|
303
606
|
@event = event
|
304
607
|
@parent = parent
|
305
|
-
@event.parent = @parent
|
306
608
|
@labels = []
|
307
|
-
|
609
|
+
on_containing
|
308
610
|
end
|
309
611
|
|
310
612
|
# Make #event a Chord# object.
|
@@ -318,7 +620,9 @@ module Alda
|
|
318
620
|
# Alda::Score.new { violin_/viola_/cello_; e; f; g}.play
|
319
621
|
# # (plays notes E, F, G with three instruments simultaneously)
|
320
622
|
def / other
|
321
|
-
|
623
|
+
unless (expected = other) == (got = @parent.events.pop)
|
624
|
+
raise OrderError.new expected, got
|
625
|
+
end
|
322
626
|
@event =
|
323
627
|
if @event.is_a? Part
|
324
628
|
Part.new @event.names + other.event.names, other.event.arg
|
@@ -339,13 +643,29 @@ module Alda
|
|
339
643
|
|
340
644
|
# Marks repetition.
|
341
645
|
def * num
|
342
|
-
@count = num
|
646
|
+
@count = (@count || 1) * num
|
647
|
+
self
|
343
648
|
end
|
344
649
|
|
345
650
|
# Marks alternative repetition.
|
346
651
|
def % labels
|
347
|
-
labels = [labels] unless labels.
|
652
|
+
labels = [labels] unless labels.is_a? Array
|
348
653
|
@labels.replace labels.to_a
|
654
|
+
self
|
655
|
+
end
|
656
|
+
|
657
|
+
def event= event
|
658
|
+
@event = event
|
659
|
+
on_containing
|
660
|
+
@event
|
661
|
+
end
|
662
|
+
|
663
|
+
def on_containing
|
664
|
+
if @event
|
665
|
+
@event.container = self
|
666
|
+
@event.parent = @parent
|
667
|
+
@event.on_contained
|
668
|
+
end
|
349
669
|
end
|
350
670
|
|
351
671
|
def method_missing name, *args
|
@@ -363,7 +683,7 @@ module Alda
|
|
363
683
|
|
364
684
|
# The arguments passed to the lisp function.
|
365
685
|
# Its elements can be
|
366
|
-
# Array#, Hash#, Numeric#, String#, Symbol#, or
|
686
|
+
# Array#, Hash#, Numeric#, String#, Symbol#, or Event#.
|
367
687
|
attr_accessor :args
|
368
688
|
|
369
689
|
# The underlines in +head+ will be converted to hyphens.
|
@@ -377,8 +697,11 @@ module Alda
|
|
377
697
|
end
|
378
698
|
|
379
699
|
def on_contained
|
700
|
+
super
|
380
701
|
@args.reverse_each do |event|
|
381
|
-
|
702
|
+
if event.is_a?(Event) && (expected = event) != (got = @parent.events.pop)
|
703
|
+
raise OrderError.new expected, got
|
704
|
+
end
|
382
705
|
end
|
383
706
|
end
|
384
707
|
end
|
@@ -394,9 +717,32 @@ module Alda
|
|
394
717
|
attr_accessor :duration
|
395
718
|
|
396
719
|
# The underlines in +duration+ will be converted to +~+.
|
720
|
+
# Exclamation mark and question mark in +duration+
|
721
|
+
# will be interpreted as accidentals in #pitch.
|
722
|
+
#
|
723
|
+
# The number of underlines at the end of +duration+ means:
|
724
|
+
# neither natural nor slur if 0,
|
725
|
+
# natural if 1,
|
726
|
+
# slur if 2,
|
727
|
+
# both natural and slur if 3.
|
397
728
|
def initialize pitch, duration
|
398
729
|
@pitch = pitch.to_s
|
399
|
-
@duration = duration.to_s.
|
730
|
+
@duration = duration.to_s.tr ?_, ?~
|
731
|
+
case @duration[-1]
|
732
|
+
when ?! # sharp
|
733
|
+
@pitch.concat ?+
|
734
|
+
@duration[-1] = ''
|
735
|
+
when ?? # flat
|
736
|
+
@pitch.concat ?-
|
737
|
+
@duration[-1] = ''
|
738
|
+
end
|
739
|
+
waves = /(?<str>~+)\z/ =~ @duration ? str.size : return
|
740
|
+
@duration[@duration.length - waves..] = ''
|
741
|
+
if waves >= 2
|
742
|
+
waves -= 2
|
743
|
+
@duration.concat ?~
|
744
|
+
end
|
745
|
+
@pitch.concat ?_ * waves
|
400
746
|
end
|
401
747
|
|
402
748
|
# Append a sharp sign after #pitch.
|
@@ -441,7 +787,7 @@ module Alda
|
|
441
787
|
|
442
788
|
# Underlines in +duration+ will be converted to +~+.
|
443
789
|
def initialize duration
|
444
|
-
@duration = duration.to_s.
|
790
|
+
@duration = duration.to_s.tr ?_, ?~
|
445
791
|
end
|
446
792
|
|
447
793
|
def to_alda_code
|
@@ -525,7 +871,7 @@ module Alda
|
|
525
871
|
attr_accessor :arg
|
526
872
|
|
527
873
|
def initialize names, arg = nil
|
528
|
-
@names = names.map { |name| name.to_s.
|
874
|
+
@names = names.map { |name| name.to_s.tr ?_, ?- }
|
529
875
|
@arg = arg
|
530
876
|
end
|
531
877
|
|
@@ -535,16 +881,29 @@ module Alda
|
|
535
881
|
result.concat ?:
|
536
882
|
end
|
537
883
|
|
884
|
+
# Enables dot accessor.
|
538
885
|
# @example
|
539
886
|
# Alda::Score.new do
|
540
887
|
# violin_/viola_/cello_('strings'); g1_1_1
|
541
888
|
# strings_.cello_; -o; c1_1_1
|
542
889
|
# end.play
|
543
890
|
def method_missing name, *args
|
544
|
-
|
545
|
-
return super unless
|
546
|
-
|
547
|
-
@names.last.concat ?.,
|
891
|
+
str = name.to_s
|
892
|
+
return super unless str[-1] == ?_
|
893
|
+
str[-1] = ''
|
894
|
+
@names.last.concat ?., str
|
895
|
+
if args.size == 1
|
896
|
+
joined = args.first
|
897
|
+
unless (got = @parent.events.pop) == (expected = joined)
|
898
|
+
raise OrderError.new expected, got
|
899
|
+
end
|
900
|
+
unless @container
|
901
|
+
@container = EventContainer.new nil, @parent
|
902
|
+
@parent.events.delete self
|
903
|
+
@parent.push @container
|
904
|
+
end
|
905
|
+
@container.event = Sequence.join self, joined
|
906
|
+
end
|
548
907
|
end
|
549
908
|
end
|
550
909
|
|
@@ -594,7 +953,7 @@ module Alda
|
|
594
953
|
|
595
954
|
# Underlines in +name+ is converted to hyphens.
|
596
955
|
def initialize name
|
597
|
-
@name = name.to_s.
|
956
|
+
@name = name.to_s.tr ?_, ?-
|
598
957
|
end
|
599
958
|
|
600
959
|
def to_alda_code
|
@@ -611,7 +970,7 @@ module Alda
|
|
611
970
|
|
612
971
|
# Underlines in +name+ is converted to hyphens.
|
613
972
|
def initialize name
|
614
|
-
@name = name.to_s.
|
973
|
+
@name = name.to_s.tr ?_, ?-
|
615
974
|
end
|
616
975
|
|
617
976
|
def to_alda_code
|
@@ -623,8 +982,94 @@ module Alda
|
|
623
982
|
class Sequence < Event
|
624
983
|
include EventList
|
625
984
|
|
985
|
+
# Using this module can fix a bug of Array#flatten.
|
986
|
+
# @example
|
987
|
+
# def (a = Object.new).method_missing(...)
|
988
|
+
# Object.new
|
989
|
+
# end
|
990
|
+
# [a].flatten rescue $! # => #<TypeError:...>
|
991
|
+
# using Alda::Sequence::RefineFlatten
|
992
|
+
# [a].flatten # => [#<Object:...>]
|
993
|
+
module RefineFlatten
|
994
|
+
refine Array do
|
995
|
+
def flatten
|
996
|
+
each_with_object [] do |element, result|
|
997
|
+
if element.is_a? Array
|
998
|
+
result.push *element.flatten
|
999
|
+
else
|
1000
|
+
result.push element
|
1001
|
+
end
|
1002
|
+
end
|
1003
|
+
end
|
1004
|
+
end
|
1005
|
+
end
|
1006
|
+
using RefineFlatten
|
1007
|
+
|
626
1008
|
def to_alda_code
|
627
1009
|
@events.to_alda_code
|
628
1010
|
end
|
1011
|
+
|
1012
|
+
# Creates a Sequence# object by joining +events+.
|
1013
|
+
# The EventContainer# objects are extracted,
|
1014
|
+
# and the Sequence# objects are flattened.
|
1015
|
+
def self.join *events
|
1016
|
+
new do
|
1017
|
+
@events = events.map do |event|
|
1018
|
+
while event.is_a?(EventContainer) && !event.count && event.labels.empty?
|
1019
|
+
event = event.event
|
1020
|
+
end
|
1021
|
+
event.is_a?(Sequence) ? event.events : event
|
1022
|
+
end.flatten
|
1023
|
+
end
|
1024
|
+
end
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
# A set-variable event.
|
1028
|
+
# Includes EventList#.
|
1029
|
+
class SetVariable < Event
|
1030
|
+
include EventList
|
1031
|
+
|
1032
|
+
# The name of the variable.
|
1033
|
+
attr_accessor :name
|
1034
|
+
|
1035
|
+
# The events passed to it using arguments instead of a block.
|
1036
|
+
attr_reader :original_events
|
1037
|
+
|
1038
|
+
def initialize name, *events, &block
|
1039
|
+
@name = name.to_sym
|
1040
|
+
@original_events = events
|
1041
|
+
@events = events.clone
|
1042
|
+
super &block
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
# Specially, the result ends with a newline.
|
1046
|
+
def to_alda_code
|
1047
|
+
"#@name = #{events_alda_codes}\n"
|
1048
|
+
end
|
1049
|
+
|
1050
|
+
def on_contained
|
1051
|
+
super
|
1052
|
+
@parent.variables.add @name
|
1053
|
+
@original_events.reverse_each do |event|
|
1054
|
+
unless (expected = event) == (got = @parent.events.pop)
|
1055
|
+
raise OrderError.new expected, got
|
1056
|
+
end
|
1057
|
+
end
|
1058
|
+
end
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
# A get-variable event
|
1062
|
+
class GetVariable < Event
|
1063
|
+
|
1064
|
+
# The name of the variable
|
1065
|
+
attr_accessor :name
|
1066
|
+
|
1067
|
+
def initialize name
|
1068
|
+
@name = name
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
def to_alda_code
|
1072
|
+
@name.to_s
|
1073
|
+
end
|
629
1074
|
end
|
630
1075
|
end
|
data/lib/alda-rb/version.rb
CHANGED
metadata
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alda-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ulysses Zhan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-04-
|
11
|
+
date: 2020-04-24 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
15
|
-
-
|
15
|
+
- UlyssesZhan@gmail.com
|
16
16
|
executables: []
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
@@ -32,6 +32,7 @@ files:
|
|
32
32
|
- examples/clapping_music.rb
|
33
33
|
- examples/dot_accessor.rb
|
34
34
|
- examples/entropy.rb
|
35
|
+
- examples/hanon.rb
|
35
36
|
- examples/hello_world.rb
|
36
37
|
- examples/key_signature.rb
|
37
38
|
- examples/midi_note_numbers.rb
|
@@ -41,6 +42,7 @@ files:
|
|
41
42
|
- examples/phase.rb
|
42
43
|
- examples/seconds_and_milliseconds.rb
|
43
44
|
- examples/showcase.rb
|
45
|
+
- examples/variables.rb
|
44
46
|
- lib/alda-rb.rb
|
45
47
|
- lib/alda-rb/version.rb
|
46
48
|
homepage: https://github.com/UlyssesZh/alda-rb
|
@@ -49,6 +51,7 @@ licenses:
|
|
49
51
|
metadata:
|
50
52
|
homepage_uri: https://github.com/UlyssesZh/alda-rb
|
51
53
|
source_code_uri: https://github.com/UlyssesZh/alda-rb
|
54
|
+
changelog_uri: https://github.com/UlyssesZh/alda-rb/releases
|
52
55
|
post_install_message:
|
53
56
|
rdoc_options: []
|
54
57
|
require_paths:
|
@@ -57,7 +60,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
60
|
requirements:
|
58
61
|
- - ">="
|
59
62
|
- !ruby/object:Gem::Version
|
60
|
-
version: 2.
|
63
|
+
version: 2.7.0
|
61
64
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
65
|
requirements:
|
63
66
|
- - ">="
|