xi-lang 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +24 -11
- data/bin/xi +0 -1
- data/lib/xi/bjorklund.rb +60 -0
- data/lib/xi/clock.rb +9 -1
- data/lib/xi/core_ext/array.rb +13 -0
- data/lib/xi/core_ext/enumerable.rb +6 -14
- data/lib/xi/core_ext/enumerator.rb +14 -0
- data/lib/xi/core_ext/fixnum.rb +3 -3
- data/lib/xi/core_ext/numeric.rb +4 -4
- data/lib/xi/core_ext/scalar.rb +16 -0
- data/lib/xi/core_ext/string.rb +46 -44
- data/lib/xi/core_ext.rb +3 -1
- data/lib/xi/pattern/generators.rb +157 -162
- data/lib/xi/pattern/transforms.rb +96 -79
- data/lib/xi/pattern.rb +424 -95
- data/lib/xi/step_sequencer.rb +40 -0
- data/lib/xi/stream.rb +56 -64
- data/lib/xi/tidal_clock.rb +2 -1
- data/lib/xi/version.rb +1 -1
- data/lib/xi.rb +12 -3
- data/xi.gemspec +0 -1
- metadata +7 -18
- data/lib/xi/core_ext/simple.rb +0 -15
- data/lib/xi/event.rb +0 -82
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bd3c1d2086dab411b68d702c8ca72ba9ba0875dc
|
4
|
+
data.tar.gz: 4a3ef7494c570a1990ae49a97a3f6d29371398cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 102013a3fb01d7764e83f9d5fa461ab430ef27153502e4f4b4bee5a1528001ef15660c0600ab1681f435defd615fdd7cd307b14958a7df0d7d2752ba7e5d3774
|
7
|
+
data.tar.gz: d94f330514d532fe1aa4de6d627ad7c8accf689f9e173fbdd4ba638d433f07c2a83db7edc081653c798a5ddfa41144e550313be4084ccc676f4a650dd3c5b39e
|
data/README.md
CHANGED
@@ -15,16 +15,25 @@ multiple known bugs, missing features, documentation and tests.
|
|
15
15
|
## Example
|
16
16
|
|
17
17
|
```ruby
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
18
|
+
melody = [1,4,7,8,9]
|
19
|
+
scale = [Scale.iwato, Scale.jiao]
|
20
|
+
|
21
|
+
fm.set degree: melody.p(1/2,1/8,1/8,1/8,1/16,1/8,1/8).seq(2),
|
22
|
+
gate: :degree,
|
23
|
+
detune: [0.1, 0.4, 0.4],
|
24
|
+
sustain: [1,2,3,10],
|
25
|
+
accelerate: [0.5, 0, 0.1],
|
26
|
+
octave: [3,4,5,6].p(1/3),
|
27
|
+
scale: scale.p(1/2),
|
28
|
+
amp: P.new { |y| y << rand * 0.2 + 0.8 }.p(1/2)
|
29
|
+
|
30
|
+
kick.set freq: s("xi.x .ix. | xi.x xx.x", 70, 200), amp: 0.8, gate: :freq
|
31
|
+
|
32
|
+
clap.set n: s("..x. xyz. .x.. .xyx", 60, 61, 60).p.decelerate(2),
|
33
|
+
gate: :n,
|
34
|
+
amp: 0.35,
|
35
|
+
pan: P.sin(16, 2) * 0.6,
|
36
|
+
sustain: 0.25
|
28
37
|
```
|
29
38
|
|
30
39
|
## Installation
|
@@ -64,8 +73,9 @@ Then:
|
|
64
73
|
|
65
74
|
$ cd xi
|
66
75
|
$ bundle install
|
76
|
+
$ rake install
|
67
77
|
|
68
|
-
You're done! Fire up the REPL
|
78
|
+
You're done! Fire up the REPL using `xi`.
|
69
79
|
|
70
80
|
## Development
|
71
81
|
|
@@ -78,6 +88,9 @@ release a new version, update the version number in `version.rb`, and then run
|
|
78
88
|
git commits and tags, and push the `.gem` file to
|
79
89
|
[rubygems.org](https://rubygems.org).
|
80
90
|
|
91
|
+
You can also try things on the REPL without installing the gem on your machine
|
92
|
+
by doing `bundle exec bin/xi`.
|
93
|
+
|
81
94
|
## Contributing
|
82
95
|
|
83
96
|
Bug reports and pull requests are welcome on GitHub at
|
data/bin/xi
CHANGED
data/lib/xi/bjorklund.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# Implementation adapted from Nebs' (MIT licensed)
|
2
|
+
# https://github.com/nebs/bjorklund-euclidean-rhythms
|
3
|
+
#
|
4
|
+
class Xi::Bjorklund
|
5
|
+
attr_reader :pulses, :slots, :value
|
6
|
+
|
7
|
+
def initialize(pulses, slots, value=nil)
|
8
|
+
@pulses = pulses.to_i
|
9
|
+
@slots = slots.to_i
|
10
|
+
@value = value || 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def p(*args, **metadata)
|
14
|
+
ary = to_a
|
15
|
+
ary.map { |v| v ? @value : nil }.p(1 / ary.size, **metadata)
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
"e(#{@pulses}, #{@slots}, #{@value.inspect})"
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
to_a.map { |i| i ? 'x' : '.' }.join
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_a
|
27
|
+
k = @pulses
|
28
|
+
n = @slots
|
29
|
+
|
30
|
+
return [] if n == 0 || k == 0
|
31
|
+
|
32
|
+
bins = []
|
33
|
+
remainders = []
|
34
|
+
k.times { |i| bins[i] = [true] }
|
35
|
+
(n-k).times { |i| remainders[i] = [false] }
|
36
|
+
|
37
|
+
return bins.flatten if n == k
|
38
|
+
|
39
|
+
loop do
|
40
|
+
new_remainders = []
|
41
|
+
bins.each_with_index do |bin, i|
|
42
|
+
if remainders.empty?
|
43
|
+
new_remainders.push bin
|
44
|
+
else
|
45
|
+
bin += remainders.shift
|
46
|
+
bins[i] = bin
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
if new_remainders.any?
|
51
|
+
bins.pop new_remainders.count
|
52
|
+
remainders = new_remainders
|
53
|
+
end
|
54
|
+
|
55
|
+
break unless remainders.size > 1
|
56
|
+
end
|
57
|
+
|
58
|
+
return (bins + remainders).flatten
|
59
|
+
end
|
60
|
+
end
|
data/lib/xi/clock.rb
CHANGED
@@ -64,6 +64,14 @@ module Xi
|
|
64
64
|
@mutex.synchronize { 1.0 / @cps }
|
65
65
|
end
|
66
66
|
|
67
|
+
def current_time
|
68
|
+
Time.now.to_f - @init_ts + @latency
|
69
|
+
end
|
70
|
+
|
71
|
+
def current_cycle
|
72
|
+
current_time * cps
|
73
|
+
end
|
74
|
+
|
67
75
|
def inspect
|
68
76
|
"#<#{self.class.name}:#{"0x%014x" % object_id} " \
|
69
77
|
"cps=#{cps.inspect} #{playing? ? :playing : :stopped}>"
|
@@ -80,7 +88,7 @@ module Xi
|
|
80
88
|
|
81
89
|
def do_tick
|
82
90
|
return unless playing?
|
83
|
-
now
|
91
|
+
now = self.current_time
|
84
92
|
cps = self.cps
|
85
93
|
@streams.each { |s| s.notify(now, cps) }
|
86
94
|
rescue => err
|
@@ -1,25 +1,17 @@
|
|
1
1
|
require 'xi/pattern'
|
2
2
|
|
3
|
-
module Xi
|
4
|
-
module
|
5
|
-
def p(
|
6
|
-
Pattern.new(self,
|
3
|
+
module Xi::CoreExt
|
4
|
+
module Enumerable
|
5
|
+
def p(*delta, **metadata)
|
6
|
+
Xi::Pattern.new(self.to_a, delta: delta, **metadata)
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
11
|
class Enumerator
|
12
|
-
include Xi::
|
13
|
-
end
|
14
|
-
|
15
|
-
class Array
|
16
|
-
include Xi::Pattern::Enumerable
|
17
|
-
end
|
18
|
-
|
19
|
-
class Hash
|
20
|
-
include Xi::Pattern::Enumerable
|
12
|
+
include Xi::CoreExt::Enumerable
|
21
13
|
end
|
22
14
|
|
23
15
|
class Range
|
24
|
-
include Xi::
|
16
|
+
include Xi::CoreExt::Enumerable
|
25
17
|
end
|
data/lib/xi/core_ext/fixnum.rb
CHANGED
data/lib/xi/core_ext/numeric.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
module Xi
|
1
|
+
module Xi::CoreExt
|
2
2
|
module Numeric
|
3
3
|
def midi_to_cps
|
4
4
|
440 * (2 ** ((self - 69) / 12.0))
|
@@ -22,13 +22,13 @@ module Xi
|
|
22
22
|
end
|
23
23
|
|
24
24
|
class Fixnum
|
25
|
-
include Xi::Numeric
|
25
|
+
include Xi::CoreExt::Numeric
|
26
26
|
end
|
27
27
|
|
28
28
|
class Float
|
29
|
-
include Xi::Numeric
|
29
|
+
include Xi::CoreExt::Numeric
|
30
30
|
end
|
31
31
|
|
32
32
|
class Rational
|
33
|
-
include Xi::Numeric
|
33
|
+
include Xi::CoreExt::Numeric
|
34
34
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'xi/pattern'
|
2
|
+
|
3
|
+
module Xi::CoreExt
|
4
|
+
module Scalar
|
5
|
+
def p(*delta, **metadata)
|
6
|
+
[self].p(*delta, **metadata)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Fixnum; include Xi::CoreExt::Scalar; end
|
12
|
+
class Float; include Xi::CoreExt::Scalar; end
|
13
|
+
class String; include Xi::CoreExt::Scalar; end
|
14
|
+
class Symbol; include Xi::CoreExt::Scalar; end
|
15
|
+
class Rational; include Xi::CoreExt::Scalar; end
|
16
|
+
class Hash; include Xi::CoreExt::Scalar; end
|
data/lib/xi/core_ext/string.rb
CHANGED
@@ -1,50 +1,52 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
1
|
+
module Xi::CoreExt
|
2
|
+
# String Inflectors, taken from ActiveSupport 5.0 source code
|
3
|
+
module String
|
4
|
+
# Converts strings to UpperCamelCase.
|
5
|
+
# If the +uppercase_first_letter+ parameter is set to false, then produces
|
6
|
+
# lowerCamelCase.
|
7
|
+
#
|
8
|
+
# Also converts '/' to '::' which is useful for converting
|
9
|
+
# paths to namespaces.
|
10
|
+
#
|
11
|
+
# camelize('active_model') # => "ActiveModel"
|
12
|
+
# camelize('active_model', false) # => "activeModel"
|
13
|
+
# camelize('active_model/errors') # => "ActiveModel::Errors"
|
14
|
+
# camelize('active_model/errors', false) # => "activeModel::Errors"
|
15
|
+
#
|
16
|
+
# As a rule of thumb you can think of +camelize+ as the inverse of
|
17
|
+
# #underscore, though there are cases where that does not hold:
|
18
|
+
#
|
19
|
+
# camelize(underscore('SSLError')) # => "SslError"
|
20
|
+
def camelize
|
21
|
+
string = self.sub(/^[a-z\d]*/) { |match| match.capitalize }
|
22
|
+
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
|
23
|
+
string.gsub!('/'.freeze, '::'.freeze)
|
24
|
+
string
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
27
|
+
# Makes an underscored, lowercase form from the expression in the string.
|
28
|
+
#
|
29
|
+
# Changes '::' to '/' to convert namespaces to paths.
|
30
|
+
#
|
31
|
+
# underscore('ActiveModel') # => "active_model"
|
32
|
+
# underscore('ActiveModel::Errors') # => "active_model/errors"
|
33
|
+
#
|
34
|
+
# As a rule of thumb you can think of +underscore+ as the inverse of
|
35
|
+
# #camelize, though there are cases where that does not hold:
|
36
|
+
#
|
37
|
+
# camelize(underscore('SSLError')) # => "SslError"
|
38
|
+
def underscore
|
39
|
+
return self unless self =~ /[A-Z-]|::/
|
40
|
+
word = self.to_s.gsub('::'.freeze, '/'.freeze)
|
41
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
|
42
|
+
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
|
43
|
+
word.tr!("-".freeze, "_".freeze)
|
44
|
+
word.downcase!
|
45
|
+
word
|
46
|
+
end
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
48
50
|
class String
|
49
|
-
include Xi::
|
51
|
+
include Xi::CoreExt::String
|
50
52
|
end
|
data/lib/xi/core_ext.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
require 'xi/core_ext/array'
|
1
2
|
require 'xi/core_ext/enumerable'
|
3
|
+
require 'xi/core_ext/enumerator'
|
2
4
|
require 'xi/core_ext/fixnum'
|
3
5
|
require 'xi/core_ext/numeric'
|
4
6
|
require 'xi/core_ext/object'
|
5
|
-
require 'xi/core_ext/
|
7
|
+
require 'xi/core_ext/scalar'
|
6
8
|
require 'xi/core_ext/string'
|