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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 38043c0ad025b398a49d63e1c93681992c0b184a
4
- data.tar.gz: fbc0e32315abf8272f388bbe59917236633a0d09
3
+ metadata.gz: bd3c1d2086dab411b68d702c8ca72ba9ba0875dc
4
+ data.tar.gz: 4a3ef7494c570a1990ae49a97a3f6d29371398cd
5
5
  SHA512:
6
- metadata.gz: 10f089d5ecb56a89e70091b2845654fdbdf7beb9c7b3fc23366038ae078769065166b3b89fd08de19fca0ec99612bce60853f16554aacb2d269036e895df4a29
7
- data.tar.gz: e4fa8eef3158cbf1d14d8f9b8d4241dfe83de117a1ef6730c947992baf555a9c110f425e9d7828eaafdf9201cf71f52d9c2cd2737100e85c198397ce22048a68
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
- k = MIDI::Stream.new
19
-
20
- k.set degree: [0, 3, 5, 7],
21
- octave: [1, 2],
22
- scale: [Scale.egyptian],
23
- voice: (0..6).p.scale(0, 6, 0, 127),
24
- vel: [30, 25, 20].p + 20,
25
- cutoff: P.sin1(32, 2) * 128,
26
- delay_feedback: 1/2 * 128,
27
- delay_time: [0, 0x7f].p(1/16)
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 from `bin/xi`.
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
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- require 'bundler/setup'
3
2
  require "xi"
4
3
  require "xi/repl"
5
4
 
@@ -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 = Time.now.to_f - @init_ts + @latency
91
+ now = self.current_time
84
92
  cps = self.cps
85
93
  @streams.each { |s| s.notify(now, cps) }
86
94
  rescue => err
@@ -0,0 +1,13 @@
1
+ require 'xi/pattern'
2
+
3
+ module Xi::CoreExt
4
+ module Array
5
+ def p(*delta, **metadata)
6
+ Xi::Pattern.new(self, delta: delta, **metadata)
7
+ end
8
+ end
9
+ end
10
+
11
+ class Array
12
+ include Xi::CoreExt::Array
13
+ end
@@ -1,25 +1,17 @@
1
1
  require 'xi/pattern'
2
2
 
3
- module Xi
4
- module Pattern::Enumerable
5
- def p(dur=nil, **metadata)
6
- Pattern.new(self, event_duration: dur, **metadata)
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::Pattern::Enumerable
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::Pattern::Enumerable
16
+ include Xi::CoreExt::Enumerable
25
17
  end
@@ -0,0 +1,14 @@
1
+ module Xi::CoreExt
2
+ module Enumerator
3
+ def next?
4
+ peek
5
+ true
6
+ rescue StopIteration
7
+ false
8
+ end
9
+ end
10
+ end
11
+
12
+ class Enumerator
13
+ include Xi::CoreExt::Enumerator
14
+ end
@@ -1,5 +1,5 @@
1
- module Xi
2
- module CoerceToRational
1
+ module Xi::CoreExt
2
+ module Fixnum
3
3
  def /(o)
4
4
  super(o.to_r)
5
5
  end
@@ -7,5 +7,5 @@ module Xi
7
7
  end
8
8
 
9
9
  class Fixnum
10
- prepend Xi::CoerceToRational
10
+ prepend Xi::CoreExt::Fixnum
11
11
  end
@@ -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
@@ -1,50 +1,52 @@
1
- # String Inflectors, taken from ActiveSupport 5.0 source code
2
- module Xi::Inflectors
3
- # Converts strings to UpperCamelCase.
4
- # If the +uppercase_first_letter+ parameter is set to false, then produces
5
- # lowerCamelCase.
6
- #
7
- # Also converts '/' to '::' which is useful for converting
8
- # paths to namespaces.
9
- #
10
- # camelize('active_model') # => "ActiveModel"
11
- # camelize('active_model', false) # => "activeModel"
12
- # camelize('active_model/errors') # => "ActiveModel::Errors"
13
- # camelize('active_model/errors', false) # => "activeModel::Errors"
14
- #
15
- # As a rule of thumb you can think of +camelize+ as the inverse of
16
- # #underscore, though there are cases where that does not hold:
17
- #
18
- # camelize(underscore('SSLError')) # => "SslError"
19
- def camelize
20
- string = self.sub(/^[a-z\d]*/) { |match| match.capitalize }
21
- string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
22
- string.gsub!('/'.freeze, '::'.freeze)
23
- string
24
- end
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
- # Makes an underscored, lowercase form from the expression in the string.
27
- #
28
- # Changes '::' to '/' to convert namespaces to paths.
29
- #
30
- # underscore('ActiveModel') # => "active_model"
31
- # underscore('ActiveModel::Errors') # => "active_model/errors"
32
- #
33
- # As a rule of thumb you can think of +underscore+ as the inverse of
34
- # #camelize, though there are cases where that does not hold:
35
- #
36
- # camelize(underscore('SSLError')) # => "SslError"
37
- def underscore
38
- return self unless self =~ /[A-Z-]|::/
39
- word = self.to_s.gsub('::'.freeze, '/'.freeze)
40
- word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
41
- word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
42
- word.tr!("-".freeze, "_".freeze)
43
- word.downcase!
44
- word
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::Inflectors
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/simple'
7
+ require 'xi/core_ext/scalar'
6
8
  require 'xi/core_ext/string'