xi-lang 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/xi/clock.rb +2 -7
- data/lib/xi/core_ext/object.rb +5 -0
- data/lib/xi/core_ext.rb +1 -0
- data/lib/xi/logger.rb +25 -0
- data/lib/xi/music_parameters.rb +47 -0
- data/lib/xi/pattern/transforms.rb +34 -9
- data/lib/xi/repl.rb +6 -2
- data/lib/xi/scale.rb +97 -0
- data/lib/xi/stream.rb +47 -31
- data/lib/xi/version.rb +1 -1
- data/lib/xi.rb +58 -8
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 65bceb35fd0dbad39331e9c89bea0a83254fe075
|
4
|
+
data.tar.gz: a20c3dd41afe001b698aab57d8cd3577e66d6dcb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e92c7bf49fa2bba86bf0eb153d7c0d1fd363a21060d52faf3a472655ffce291c8e57563edc303ae1ef65c591dc6b6db746d2f64592e469e927ba56a35ce6cd31
|
7
|
+
data.tar.gz: 3ab57ef7a85d4cac9a9e260aba0b030972b80105e320036feefc3ef3a418b22aec361180685cdda28ef92ab72ee39639ca7786595c030000b96f76d4b04c5be5
|
data/lib/xi/clock.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'thread'
|
2
|
-
require 'logger'
|
3
2
|
require 'set'
|
4
3
|
|
5
4
|
Thread.abort_on_exception = true
|
@@ -7,7 +6,7 @@ Thread.abort_on_exception = true
|
|
7
6
|
module Xi
|
8
7
|
class Clock
|
9
8
|
DEFAULT_CPS = 1.0
|
10
|
-
INTERVAL_SEC =
|
9
|
+
INTERVAL_SEC = 10 / 1000.0
|
11
10
|
|
12
11
|
def initialize(cps: DEFAULT_CPS)
|
13
12
|
@mutex = Mutex.new
|
@@ -83,11 +82,7 @@ module Xi
|
|
83
82
|
return unless playing?
|
84
83
|
@streams.each { |s| s.notify(cycles) }
|
85
84
|
rescue => err
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
def logger
|
90
|
-
@logger ||= Logger.new(STDOUT)
|
85
|
+
error(err)
|
91
86
|
end
|
92
87
|
end
|
93
88
|
end
|
data/lib/xi/core_ext.rb
CHANGED
data/lib/xi/logger.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
module Xi::Logger
|
5
|
+
LOG_FILE = File.join(Dir.tmpdir, 'xi.log')
|
6
|
+
|
7
|
+
def logger
|
8
|
+
@@logger ||= begin
|
9
|
+
logger = ::Logger.new(LOG_FILE)
|
10
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
11
|
+
"[#{datetime.strftime("%F %T %L")}] #{msg}\n"
|
12
|
+
end
|
13
|
+
logger
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def debug(*args)
|
18
|
+
logger.debug(args.map(&:to_s).join(' '.freeze))
|
19
|
+
end
|
20
|
+
|
21
|
+
def error(error)
|
22
|
+
logger.error("#{error}:\n#{error.backtrace.join("\n".freeze)}")
|
23
|
+
ErrorLog.instance << error.to_s
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'xi/scale'
|
2
|
+
|
3
|
+
class Xi::Stream
|
4
|
+
module MusicParameters
|
5
|
+
DEFAULT = {
|
6
|
+
degree: 0,
|
7
|
+
octave: 5,
|
8
|
+
root: 0,
|
9
|
+
scale: Xi::Scale.major,
|
10
|
+
steps_per_octave: 12,
|
11
|
+
}
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def transform_state
|
16
|
+
super
|
17
|
+
|
18
|
+
@state = DEFAULT.merge(@state)
|
19
|
+
|
20
|
+
if !changed_param?(:note) && changed_param?(:degree, :scale, :steps_per_octave)
|
21
|
+
@state[:note] = reduce_to_note
|
22
|
+
@changed_params << :note
|
23
|
+
end
|
24
|
+
|
25
|
+
if !changed_param?(:midinote) && changed_param?(:note)
|
26
|
+
@state[:midinote] = reduce_to_midinote
|
27
|
+
@changed_params << :midinote
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def reduce_to_midinote
|
32
|
+
Array(@state[:note]).compact.map { |n|
|
33
|
+
@state[:root].to_i + @state[:octave].to_i * @state[:steps_per_octave] + n
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def reduce_to_note
|
38
|
+
Array(@state[:degree]).compact.map do |d|
|
39
|
+
d.degree_to_key(Array(@state[:scale]), @state[:steps_per_octave])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def changed_param?(*params)
|
44
|
+
@changed_params.any? { |p| params.include?(p) }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -210,18 +210,33 @@ module Xi
|
|
210
210
|
end
|
211
211
|
end
|
212
212
|
|
213
|
-
# Traverses the pattern in order and then in reverse order
|
213
|
+
# Traverses the pattern in order and then in reverse order, skipping
|
214
|
+
# first and last values if +skip_extremes+ is true.
|
214
215
|
#
|
215
216
|
# @example
|
216
|
-
# peek (0..3).p.bounce #=> [0, 1, 2, 3,
|
217
|
+
# peek (0..3).p.bounce #=> [0, 1, 2, 3, 2, 1]
|
218
|
+
# peek 10.p.bounce #=> [10]
|
217
219
|
#
|
220
|
+
# @example with skip_extremes=false
|
221
|
+
# peek (0..3).p.bounce(false) #=> [0, 1, 2, 3, 3, 2, 1, 0]
|
222
|
+
#
|
223
|
+
# @param skip_extremes [Boolean] Skip first and last values
|
224
|
+
# to avoid repeated values (default: true)
|
218
225
|
# @return [Pattern]
|
219
226
|
#
|
220
|
-
def bounce
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
227
|
+
def bounce(skip_extremes=true)
|
228
|
+
return self if size == 0 || size == 1
|
229
|
+
|
230
|
+
Pattern.new(self, size: size * 2 - 1) { |y|
|
231
|
+
last_id = 0
|
232
|
+
each.with_index { |v, i|
|
233
|
+
y << v
|
234
|
+
last_id = i
|
235
|
+
}
|
236
|
+
reverse_each.with_index { |v, i|
|
237
|
+
y << v unless skip_extremes && (i == 0 || i == last_id)
|
238
|
+
}
|
239
|
+
}
|
225
240
|
end
|
226
241
|
|
227
242
|
# Normalizes a pattern of values that range from +min+ to +max+ to 0..1
|
@@ -306,7 +321,12 @@ module Xi
|
|
306
321
|
#
|
307
322
|
def sometimes(probability=0.5)
|
308
323
|
prob_pat = probability.p
|
309
|
-
|
324
|
+
|
325
|
+
if times_pat.infinite?
|
326
|
+
fail ArgumentError, 'times must be a finite pattern'
|
327
|
+
end
|
328
|
+
|
329
|
+
Pattern.new(self, size: size * prob_pat.reduce(:+)) do |y|
|
310
330
|
prob_pat.each do |prob|
|
311
331
|
each { |v| y << (rand < prob ? v : nil) }
|
312
332
|
end
|
@@ -318,7 +338,12 @@ module Xi
|
|
318
338
|
#
|
319
339
|
def repeat_each(times)
|
320
340
|
times_pat = times.p
|
321
|
-
|
341
|
+
|
342
|
+
if times_pat.infinite?
|
343
|
+
fail ArgumentError, 'times must be a finite pattern'
|
344
|
+
end
|
345
|
+
|
346
|
+
Pattern.new(self, size: size * times_pat.reduce(:+)) do |y|
|
322
347
|
times_pat.each do |t|
|
323
348
|
each { |v| t.times { y << v } }
|
324
349
|
end
|
data/lib/xi/repl.rb
CHANGED
@@ -37,12 +37,16 @@ module Xi
|
|
37
37
|
Pry.hooks.add_hook(:after_eval, "check_for_errors") do |result, pry|
|
38
38
|
more_errors = ErrorLog.instance.more_errors?
|
39
39
|
ErrorLog.instance.each do |msg|
|
40
|
-
puts "
|
40
|
+
puts red("Error: #{msg}")
|
41
41
|
end
|
42
|
-
puts "
|
42
|
+
puts red("There were more errors...") if more_errors
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
def red(string)
|
47
|
+
"\e[31m\e[1m#{string}\e[22m\e[0m"
|
48
|
+
end
|
49
|
+
|
46
50
|
def load_init_script
|
47
51
|
require(init_script_path)
|
48
52
|
end
|
data/lib/xi/scale.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
class Xi::Scale
|
2
|
+
DEGREES = {
|
3
|
+
# TWELVE TONES PER OCTAVE
|
4
|
+
# 5 note scales
|
5
|
+
minorPentatonic: [0,3,5,7,10],
|
6
|
+
majorPentatonic: [0,2,4,7,9],
|
7
|
+
# another mode of major pentatonic
|
8
|
+
ritusen: [0,2,5,7,9],
|
9
|
+
# another mode of major pentatonic
|
10
|
+
egyptian: [0,2,5,7,10],
|
11
|
+
|
12
|
+
kumoi: [0,2,3,7,9],
|
13
|
+
hirajoshi: [0,2,3,7,8],
|
14
|
+
|
15
|
+
iwato: [0,1,5,6,10], # mode of hirajoshi
|
16
|
+
chinese: [0,4,6,7,11], # mode of hirajoshi
|
17
|
+
indian: [0,4,5,7,10],
|
18
|
+
pelog: [0,1,3,7,8],
|
19
|
+
|
20
|
+
prometheus: [0,2,4,6,11],
|
21
|
+
scriabin: [0,1,4,7,9],
|
22
|
+
|
23
|
+
# han chinese pentatonic scales
|
24
|
+
gong: [0,2,4,7,9],
|
25
|
+
shang: [0,2,5,7,10],
|
26
|
+
jiao: [0,3,5,8,10],
|
27
|
+
zhi: [0,2,5,7,9],
|
28
|
+
yu: [0,3,5,7,10],
|
29
|
+
|
30
|
+
# 6 note scales
|
31
|
+
whole: [0, 2, 4, 6, 8, 10],
|
32
|
+
augmented: [0,3,4,7,8,11],
|
33
|
+
augmented2: [0,1,4,5,8,9],
|
34
|
+
|
35
|
+
# hexatonic modes with no tritone
|
36
|
+
hexMajor7: [0,2,4,7,9,11],
|
37
|
+
hexDorian: [0,2,3,5,7,10],
|
38
|
+
hexPhrygian: [0,1,3,5,8,10],
|
39
|
+
hexSus: [0,2,5,7,9,10],
|
40
|
+
hexMajor6: [0,2,4,5,7,9],
|
41
|
+
hexAeolian: [0,3,5,7,8,10],
|
42
|
+
|
43
|
+
# 7 note scales
|
44
|
+
major: [0,2,4,5,7,9,11],
|
45
|
+
ionian: [0,2,4,5,7,9,11],
|
46
|
+
dorian: [0,2,3,5,7,9,10],
|
47
|
+
phrygian: [0,1,3,5,7,8,10],
|
48
|
+
lydian: [0,2,4,6,7,9,11],
|
49
|
+
mixolydian: [0,2,4,5,7,9,10],
|
50
|
+
aeolian: [0,2,3,5,7,8,10],
|
51
|
+
minor: [0,2,3,5,7,8,10],
|
52
|
+
locrian: [0,1,3,5,6,8,10],
|
53
|
+
|
54
|
+
harmonicMinor: [0,2,3,5,7,8,11],
|
55
|
+
harmonicMajor: [0,2,4,5,7,8,11],
|
56
|
+
|
57
|
+
melodicMinor: [0,2,3,5,7,9,11],
|
58
|
+
melodicMinorDesc: [0,2,3,5,7,8,10],
|
59
|
+
melodicMajor: [0,2,4,5,7,8,10],
|
60
|
+
|
61
|
+
bartok: [0,2,4,5,7,8,10],
|
62
|
+
hindu: [0,2,4,5,7,8,10],
|
63
|
+
|
64
|
+
# raga modes
|
65
|
+
todi: [0,1,3,6,7,8,11],
|
66
|
+
purvi: [0,1,4,6,7,8,11],
|
67
|
+
marva: [0,1,4,6,7,9,11],
|
68
|
+
bhairav: [0,1,4,5,7,8,11],
|
69
|
+
ahirbhairav: [0,1,4,5,7,9,10],
|
70
|
+
|
71
|
+
superLocrian: [0,1,3,4,6,8,10],
|
72
|
+
romanianMinor: [0,2,3,6,7,9,10],
|
73
|
+
hungarianMinor: [0,2,3,6,7,8,11],
|
74
|
+
neapolitanMinor: [0,1,3,5,7,8,11],
|
75
|
+
enigmatic: [0,1,4,6,8,10,11],
|
76
|
+
spanish: [0,1,4,5,7,8,10],
|
77
|
+
|
78
|
+
# modes of whole tones with added note ->
|
79
|
+
leadingWhole: [0,2,4,6,8,10,11],
|
80
|
+
lydianMinor: [0,2,4,6,7,8,10],
|
81
|
+
neapolitanMajor: [0,1,3,5,7,9,11],
|
82
|
+
locrianMajor: [0,2,4,5,6,8,10],
|
83
|
+
|
84
|
+
# 8 note scales
|
85
|
+
diminished: [0,1,3,4,6,7,9,10],
|
86
|
+
diminished2: [0,2,3,5,6,8,9,11],
|
87
|
+
|
88
|
+
# 12 note scales
|
89
|
+
chromatic: (0..11).to_a,
|
90
|
+
}
|
91
|
+
|
92
|
+
class << self
|
93
|
+
DEGREES.each do |name, list|
|
94
|
+
define_method(name) { list }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/xi/stream.rb
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
require 'set'
|
2
|
+
require 'xi/music_parameters'
|
2
3
|
|
3
4
|
module Xi
|
4
5
|
class Stream
|
5
|
-
|
6
|
+
prepend MusicParameters
|
7
|
+
|
8
|
+
attr_reader :clock, :opts, :source, :state, :event_duration, :gate
|
9
|
+
|
10
|
+
def initialize(name, clock, **opts)
|
11
|
+
@name = name.to_sym
|
12
|
+
@opts = opts
|
6
13
|
|
7
|
-
def initialize(clock)
|
8
14
|
@mutex = Mutex.new
|
9
15
|
@playing = false
|
10
16
|
@last_sound_object_id = 0
|
@@ -18,6 +24,7 @@ module Xi
|
|
18
24
|
|
19
25
|
def set(event_duration: nil, gate: nil, **source)
|
20
26
|
@mutex.synchronize do
|
27
|
+
source[:s] ||= @name
|
21
28
|
@source = source
|
22
29
|
@gate = gate if gate
|
23
30
|
@event_duration = event_duration if event_duration
|
@@ -26,7 +33,7 @@ module Xi
|
|
26
33
|
play
|
27
34
|
self
|
28
35
|
end
|
29
|
-
alias_method
|
36
|
+
alias_method :call, :set
|
30
37
|
|
31
38
|
def event_duration=(new_value)
|
32
39
|
@mutex.synchronize do
|
@@ -76,10 +83,11 @@ module Xi
|
|
76
83
|
alias_method :pause, :play
|
77
84
|
|
78
85
|
def inspect
|
79
|
-
"#<#{self.class.name}:#{
|
80
|
-
"
|
86
|
+
"#<#{self.class.name} :#{@name} " \
|
87
|
+
"#{playing? ? :playing : :stopped} at #{@clock.cps}cps" \
|
88
|
+
"#{" #{@opts}" if @opts.any?}>"
|
81
89
|
rescue => err
|
82
|
-
|
90
|
+
error(err)
|
83
91
|
end
|
84
92
|
|
85
93
|
def notify(now)
|
@@ -89,9 +97,10 @@ module Xi
|
|
89
97
|
@changed_params.clear
|
90
98
|
|
91
99
|
forward_enums(now) if @must_forward
|
100
|
+
gate_off = gate_off_old_sound_objects(now)
|
101
|
+
gate_on = play_enums(now)
|
92
102
|
|
93
|
-
|
94
|
-
|
103
|
+
# Call hooks
|
95
104
|
do_gate_off_change(gate_off) unless gate_off.empty?
|
96
105
|
do_state_change if state_changed?
|
97
106
|
do_gate_on_change(gate_on) unless gate_on.empty?
|
@@ -106,6 +115,8 @@ module Xi
|
|
106
115
|
|
107
116
|
def forward_enums(now)
|
108
117
|
@enums.each do |p, (enum, total_dur)|
|
118
|
+
next if total_dur == 0
|
119
|
+
|
109
120
|
cur_pos = now % total_dur
|
110
121
|
start_pos = now - cur_pos
|
111
122
|
|
@@ -123,34 +134,40 @@ module Xi
|
|
123
134
|
@must_forward = false
|
124
135
|
end
|
125
136
|
|
126
|
-
def
|
137
|
+
def gate_off_old_sound_objects(now)
|
127
138
|
gate_off = []
|
139
|
+
|
140
|
+
# Check if there are any currently playing sound objects that
|
141
|
+
# must be gated off
|
142
|
+
@playing_sound_objects.dup.each do |end_pos, h|
|
143
|
+
if now >= h[:at] - latency_sec
|
144
|
+
gate_off << h
|
145
|
+
@playing_sound_objects.delete(end_pos)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
gate_off
|
150
|
+
end
|
151
|
+
|
152
|
+
def play_enums(now)
|
128
153
|
gate_on = []
|
129
154
|
|
130
155
|
@enums.each do |p, (enum, total_dur)|
|
156
|
+
next if total_dur == 0
|
157
|
+
|
131
158
|
cur_pos = now % total_dur
|
132
159
|
start_pos = now - cur_pos
|
133
160
|
|
134
|
-
# Check if there are any currently playing sound objects that
|
135
|
-
# must be gated off
|
136
|
-
@playing_sound_objects.dup.each do |end_pos, h|
|
137
|
-
if now >= h[:at] - latency_sec
|
138
|
-
gate_off << h
|
139
|
-
@playing_sound_objects.delete(end_pos)
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
161
|
next_ev = enum.peek
|
144
162
|
|
145
163
|
# Do we need to play next event now? If not, skip this parameter
|
146
164
|
if (@prev_end[p].nil? || now >= @prev_end[p]) && cur_pos >= next_ev.start - latency_sec
|
147
|
-
#logger.info "cur_pos=#{cur_pos} >= next_ev.start=#{next_ev.start}"
|
148
165
|
# Update state based on pattern value
|
149
166
|
# TODO: Pass as parameter exact time (start_ts + next_ev.start)
|
150
167
|
update_state(p, next_ev.value)
|
168
|
+
transform_state
|
151
169
|
|
152
|
-
# If
|
153
|
-
# a new sound object
|
170
|
+
# If a gate parameter changed, create a new sound object
|
154
171
|
if p == @gate
|
155
172
|
new_so_ids = Array(next_ev.value)
|
156
173
|
.size.times.map { new_sound_object_id }
|
@@ -173,7 +190,11 @@ module Xi
|
|
173
190
|
end
|
174
191
|
end
|
175
192
|
|
176
|
-
|
193
|
+
gate_on
|
194
|
+
end
|
195
|
+
|
196
|
+
# @override
|
197
|
+
def transform_state
|
177
198
|
end
|
178
199
|
|
179
200
|
def new_sound_object_id
|
@@ -189,21 +210,21 @@ module Xi
|
|
189
210
|
end
|
190
211
|
|
191
212
|
def do_gate_on_change(ss)
|
192
|
-
|
213
|
+
debug "Gate on change: #{ss}"
|
193
214
|
end
|
194
215
|
|
195
216
|
def do_gate_off_change(ss)
|
196
|
-
|
217
|
+
debug "Gate off change: #{ss}"
|
197
218
|
end
|
198
219
|
|
199
220
|
def do_state_change
|
200
|
-
|
221
|
+
debug "State change: #{@state
|
201
222
|
.select { |k, v| @changed_params.include?(k) }.to_h}"
|
202
223
|
end
|
203
224
|
|
204
225
|
def update_state(p, v)
|
205
226
|
if v != @state[p]
|
206
|
-
|
227
|
+
debug "Update state of :#{p}: #{v}"
|
207
228
|
@changed_params << p
|
208
229
|
@state[p] = v
|
209
230
|
end
|
@@ -220,10 +241,5 @@ module Xi
|
|
220
241
|
def latency_sec
|
221
242
|
0.05
|
222
243
|
end
|
223
|
-
|
224
|
-
def logger
|
225
|
-
# FIXME this should be configurable
|
226
|
-
@logger ||= Logger.new("/tmp/xi.log")
|
227
|
-
end
|
228
244
|
end
|
229
245
|
end
|
data/lib/xi/version.rb
CHANGED
data/lib/xi.rb
CHANGED
@@ -9,18 +9,68 @@ def inf
|
|
9
9
|
Float::INFINITY
|
10
10
|
end
|
11
11
|
|
12
|
-
module Xi
|
13
|
-
def
|
14
|
-
@
|
12
|
+
module Xi
|
13
|
+
def self.default_backend
|
14
|
+
@default_backend
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
|
17
|
+
def self.default_backend=(new_name)
|
18
|
+
@default_backend = new_name && new_name.to_sym
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
pattern
|
21
|
+
module Init
|
22
|
+
def peek(pattern, *args)
|
23
|
+
pattern.peek(*args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def peek_events(pattern, *args)
|
27
|
+
pattern.peek_events(*args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def clock
|
31
|
+
@default_clock ||= Clock.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def stop_all
|
35
|
+
@streams.each do |backend, ss|
|
36
|
+
ss.each do |name, stream|
|
37
|
+
stream.stop
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
alias_method :hush, :stop_all
|
42
|
+
|
43
|
+
def method_missing(method, backend=nil, **opts)
|
44
|
+
backend ||= Xi.default_backend
|
45
|
+
super if backend.nil?
|
46
|
+
|
47
|
+
if !backend.is_a?(String) && !backend.is_a?(Symbol)
|
48
|
+
fail ArgumentError, "invalid backend '#{backend}'"
|
49
|
+
end
|
50
|
+
|
51
|
+
@streams ||= {}
|
52
|
+
@streams[backend] ||= {}
|
53
|
+
|
54
|
+
s = @streams[backend][method] ||= begin
|
55
|
+
require "xi/#{backend}"
|
56
|
+
cls = Class.const_get("#{backend.to_s.capitalize}::Stream")
|
57
|
+
cls.new(method, self.clock, **opts)
|
58
|
+
end
|
59
|
+
|
60
|
+
b = Pry.binding_for(self)
|
61
|
+
b.local_variable_set(method, s)
|
62
|
+
|
63
|
+
s
|
64
|
+
end
|
23
65
|
end
|
24
66
|
end
|
25
67
|
|
26
|
-
|
68
|
+
singleton_class.include Xi::Init
|
69
|
+
|
70
|
+
# Try to load Supercollider backend and set it as default if installed
|
71
|
+
begin
|
72
|
+
require "xi/supercollider"
|
73
|
+
Xi.default_backend = :supercollider
|
74
|
+
rescue LoadError
|
75
|
+
Xi.default_backend = nil
|
76
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xi-lang
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Damián Silvani
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -133,13 +133,17 @@ files:
|
|
133
133
|
- lib/xi/core_ext/enumerable.rb
|
134
134
|
- lib/xi/core_ext/fixnum.rb
|
135
135
|
- lib/xi/core_ext/numeric.rb
|
136
|
+
- lib/xi/core_ext/object.rb
|
136
137
|
- lib/xi/core_ext/simple.rb
|
137
138
|
- lib/xi/error_log.rb
|
138
139
|
- lib/xi/event.rb
|
140
|
+
- lib/xi/logger.rb
|
141
|
+
- lib/xi/music_parameters.rb
|
139
142
|
- lib/xi/pattern.rb
|
140
143
|
- lib/xi/pattern/generators.rb
|
141
144
|
- lib/xi/pattern/transforms.rb
|
142
145
|
- lib/xi/repl.rb
|
146
|
+
- lib/xi/scale.rb
|
143
147
|
- lib/xi/stream.rb
|
144
148
|
- lib/xi/version.rb
|
145
149
|
- xi.gemspec
|