alda-rb 0.1.2 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
- - ">="
|