xi-lang 0.1.6 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +17 -15
- data/lib/xi/core_ext/integer.rb +11 -0
- data/lib/xi/core_ext/numeric.rb +2 -8
- data/lib/xi/core_ext/scalar.rb +1 -6
- data/lib/xi/core_ext.rb +1 -1
- data/lib/xi/osc/version.rb +5 -0
- data/lib/xi/osc.rb +36 -0
- data/lib/xi/pattern/generators.rb +7 -7
- data/lib/xi/pattern/transforms.rb +9 -9
- data/lib/xi/pattern.rb +4 -4
- data/lib/xi/supercollider/stream.rb +128 -0
- data/lib/xi/supercollider/version.rb +5 -0
- data/lib/xi/supercollider.rb +8 -0
- data/lib/xi/version.rb +1 -1
- data/synthdefs/other.scd +43 -0
- data/synthdefs/superdirt.scd +322 -0
- metadata +11 -5
- data/lib/xi/core_ext/fixnum.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2354b1293961d34731653d4461341638cc38e733a0c762b29ad8a7cc7574a7b
|
4
|
+
data.tar.gz: 3a3f2e8f0ce893304cde881800c03c33fe14e9ef01e76ba9810c1a2c3f9d8348
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b13a449ea692bfafc775fe0af0d05997655d15493e33bc2849d77e7237c58a4bdd5af89f9962c97eb265462fa353b5b468678cdf1ffe416e90b7c716b663151b
|
7
|
+
data.tar.gz: fdaaf2a270cf50cbe45de430b23269cd5e30d43ca145bd4d691a19801e3e355df1f3ba6c99f9b33d9eab3ec6e80ac257b3cb95e8c7fb066036ba0025d3ab1d02
|
data/README.md
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
# Xi [![Build Status](https://travis-ci.org/xi-livecode/xi.svg?branch=master)](https://travis-ci.org/xi-livecode/xi)
|
2
2
|
|
3
|
-
Xi
|
4
|
-
|
5
|
-
|
3
|
+
Xi is a musical pattern language inspired in Tidal and SuperCollider for
|
4
|
+
building higher-level musical constructs easily. It is implemented on the Ruby
|
5
|
+
programming language and uses SuperCollider as a backend.
|
6
6
|
|
7
|
-
Xi is only a patterns library, but can talk to
|
8
|
-
|
9
|
-
|
10
|
-
- MIDI devices
|
7
|
+
Xi is only a patterns library, but can talk to
|
8
|
+
[SuperCollider](https://github.com/supercollider/supercollider) synths or MIDI
|
9
|
+
devices.
|
11
10
|
|
12
11
|
*NOTE*: Be advised that this project is in very early alpha stages. There are a
|
13
12
|
multiple known bugs, missing features, documentation and tests.
|
@@ -40,17 +39,20 @@ clap.set n: s("..x. xyz. .x.. .xyx", 60, 61, 60).p.decelerate(2),
|
|
40
39
|
|
41
40
|
### Quickstart
|
42
41
|
|
43
|
-
You will need Ruby 2.
|
44
|
-
|
45
|
-
|
42
|
+
You will need Ruby 2.4+ installed on your system. Check by running `ruby -v`.
|
43
|
+
To install Xi you must install the core libraries and REPL, and then one or
|
44
|
+
more backends.
|
45
|
+
|
46
|
+
$ gem install xi-lang
|
46
47
|
|
47
|
-
|
48
|
+
Available backends:
|
48
49
|
|
49
|
-
|
50
|
+
* xi-midi: MIDI devices support
|
51
|
+
* xi-superdirt: [SuperDirt](https://github.com/musikinformatik/SuperDirt) backend
|
50
52
|
|
51
|
-
|
53
|
+
For example:
|
52
54
|
|
53
|
-
$ gem install xi-lang xi-
|
55
|
+
$ gem install xi-lang xi-superdirt
|
54
56
|
|
55
57
|
Then run Xi REPL with:
|
56
58
|
|
@@ -100,4 +102,4 @@ the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
|
100
102
|
|
101
103
|
## License
|
102
104
|
|
103
|
-
See [LICENSE](LICENSE)
|
105
|
+
See [LICENSE](LICENSE.txt)
|
data/lib/xi/core_ext/numeric.rb
CHANGED
@@ -21,14 +21,8 @@ module Xi::CoreExt
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
include Xi::CoreExt::Numeric
|
27
|
-
end
|
28
|
-
else
|
29
|
-
class Integer
|
30
|
-
include Xi::CoreExt::Numeric
|
31
|
-
end
|
24
|
+
class Integer
|
25
|
+
include Xi::CoreExt::Numeric
|
32
26
|
end
|
33
27
|
|
34
28
|
class Float
|
data/lib/xi/core_ext/scalar.rb
CHANGED
@@ -8,12 +8,7 @@ module Xi::CoreExt
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
class Fixnum; include Xi::CoreExt::Scalar; end
|
13
|
-
else
|
14
|
-
class Integer; include Xi::CoreExt::Scalar; end
|
15
|
-
end
|
16
|
-
|
11
|
+
class Integer; include Xi::CoreExt::Scalar; end
|
17
12
|
class Float; include Xi::CoreExt::Scalar; end
|
18
13
|
class String; include Xi::CoreExt::Scalar; end
|
19
14
|
class Symbol; include Xi::CoreExt::Scalar; end
|
data/lib/xi/core_ext.rb
CHANGED
data/lib/xi/osc.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require "xi/osc/version"
|
2
|
+
require 'osc-ruby'
|
3
|
+
|
4
|
+
module Xi
|
5
|
+
module OSC
|
6
|
+
def initialize(name, clock, server: 'localhost', port:, **opts)
|
7
|
+
super
|
8
|
+
@osc = ::OSC::Client.new(server, port)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def send_msg(address, *args)
|
14
|
+
msg = message(address, *args)
|
15
|
+
debug(__method__, msg.address, *msg.to_a)
|
16
|
+
send_osc_msg(msg)
|
17
|
+
end
|
18
|
+
|
19
|
+
def send_bundle(address, *args, at: Time.now)
|
20
|
+
msg = message(address, *args)
|
21
|
+
bundle = ::OSC::Bundle.new(at, msg)
|
22
|
+
debug(__method__, msg.address, at.to_i, at.usec, *msg.to_a)
|
23
|
+
send_osc_msg(bundle)
|
24
|
+
end
|
25
|
+
|
26
|
+
def message(address, *args)
|
27
|
+
::OSC::Message.new(address, *args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def send_osc_msg(msg)
|
31
|
+
@osc.send(msg)
|
32
|
+
rescue StandardError => err
|
33
|
+
error(err)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -61,7 +61,7 @@ module Xi
|
|
61
61
|
# peek P.rand([1, 2, 3, 4], 6) #=> [1, 3, 2, 2, 4, 3]
|
62
62
|
#
|
63
63
|
# @param list [#each] list of values
|
64
|
-
# @param repeats [
|
64
|
+
# @param repeats [Integer, Symbol] number or inf (default: 1)
|
65
65
|
# @return [Pattern]
|
66
66
|
#
|
67
67
|
def rand(list, repeats=1)
|
@@ -83,7 +83,7 @@ module Xi
|
|
83
83
|
# peek P.xrand([1, 2, 3], 8) #=> [1, 3, 2, 3, 1, 2, 3, 2]
|
84
84
|
#
|
85
85
|
# @param list [#each] list of values
|
86
|
-
# @param repeats [
|
86
|
+
# @param repeats [Integer, Symbol] number or inf (default: 1)
|
87
87
|
# @return [Pattern]
|
88
88
|
#
|
89
89
|
def xrand(list, repeats=1)
|
@@ -109,7 +109,7 @@ module Xi
|
|
109
109
|
# peek P.shuf([1, 2, 3], 3) #=> [2, 3, 1, 2, 3, 1, 2, 3, 1]
|
110
110
|
#
|
111
111
|
# @param list [#each] list of values
|
112
|
-
# @param repeats [
|
112
|
+
# @param repeats [Integer, Symbol] number or inf (default: 1)
|
113
113
|
# @return [Pattern]
|
114
114
|
#
|
115
115
|
def shuf(list, repeats=1)
|
@@ -137,8 +137,8 @@ module Xi
|
|
137
137
|
# P.sin(22).duration #=> (1/1)
|
138
138
|
# P.sin(19, 2).duration #=> (2/1)
|
139
139
|
#
|
140
|
-
# @param quant [
|
141
|
-
# @param delta [
|
140
|
+
# @param quant [Integer]
|
141
|
+
# @param delta [Integer] (default: 1)
|
142
142
|
# @return [Pattern]
|
143
143
|
#
|
144
144
|
def sin(quant, delta=1)
|
@@ -160,8 +160,8 @@ module Xi
|
|
160
160
|
# peek P.sin1(8).map { |i| i.round(2) }
|
161
161
|
# #=> [0.5, 0.85, 1.0, 0.85, 0.5, 0.15, 0.0, 0.15]
|
162
162
|
#
|
163
|
-
# @param quant [
|
164
|
-
# @param delta [
|
163
|
+
# @param quant [Integer]
|
164
|
+
# @param delta [Integer] (default: 1)
|
165
165
|
# @return [Pattern]
|
166
166
|
#
|
167
167
|
def sin1(quant, delta=1)
|
@@ -132,17 +132,17 @@ module Xi
|
|
132
132
|
# peek [1, 2, 3].p.seq(1, 1) #=> [2, 3, 1]
|
133
133
|
# peek [1, 2, 3].p.seq(2, 2) #=> [3, 2, 1, 3, 2, 1]
|
134
134
|
#
|
135
|
-
# @param repeats [
|
136
|
-
# @param offset [
|
135
|
+
# @param repeats [Integer] number (defaut: 1)
|
136
|
+
# @param offset [Integer] (default: 0)
|
137
137
|
# @return [Pattern]
|
138
138
|
#
|
139
139
|
def seq(repeats=1, offset=0)
|
140
|
-
unless repeats.is_a?(
|
141
|
-
fail ArgumentError, "repeats must be a non-negative
|
140
|
+
unless repeats.is_a?(Integer) && repeats >= 0
|
141
|
+
fail ArgumentError, "repeats must be a non-negative Integer"
|
142
142
|
end
|
143
143
|
|
144
|
-
unless offset.is_a?(
|
145
|
-
fail ArgumentError, "offset must be a non-negative
|
144
|
+
unless offset.is_a?(Integer) && offset >= 0
|
145
|
+
fail ArgumentError, "offset must be a non-negative Integer"
|
146
146
|
end
|
147
147
|
|
148
148
|
Pattern.new(self, size: size * repeats) do |y|
|
@@ -362,7 +362,7 @@ module Xi
|
|
362
362
|
# peek [1, 2, 3].p.rand #=> [2]
|
363
363
|
# peek [1, 2, 3, 4].p.rand(6) #=> [1, 3, 2, 2, 4, 3]
|
364
364
|
#
|
365
|
-
# @param repeats [
|
365
|
+
# @param repeats [Integer, Symbol] number or inf (default: 1)
|
366
366
|
# @return [Pattern]
|
367
367
|
#
|
368
368
|
def rand(repeats=1)
|
@@ -378,7 +378,7 @@ module Xi
|
|
378
378
|
# peek [1, 2, 3, 4, 5].p.xrand #=> [4]
|
379
379
|
# peek [1, 2, 3].p.xrand(8) #=> [1, 3, 2, 3, 1, 2, 3, 2]
|
380
380
|
#
|
381
|
-
# @param repeats [
|
381
|
+
# @param repeats [Integer, Symbol] number or inf (default: 1)
|
382
382
|
# @return [Pattern]
|
383
383
|
#
|
384
384
|
def xrand(repeats=1)
|
@@ -394,7 +394,7 @@ module Xi
|
|
394
394
|
# peek [1, 2, 3, 4, 5].p.xrand #=> [4]
|
395
395
|
# peek [1, 2, 3].p.xrand(8) #=> [1, 3, 2, 3, 1, 2, 3, 2]
|
396
396
|
#
|
397
|
-
# @param repeats [
|
397
|
+
# @param repeats [Integer, Symbol] number or inf (default: 1)
|
398
398
|
# @return [Pattern]
|
399
399
|
#
|
400
400
|
def shuf(repeats=1)
|
data/lib/xi/pattern.rb
CHANGED
@@ -59,7 +59,7 @@ module Xi
|
|
59
59
|
# # [3, 4, 1, 0]]
|
60
60
|
#
|
61
61
|
# @param source [Array]
|
62
|
-
# @param size [
|
62
|
+
# @param size [Integer] number of events per iteration
|
63
63
|
# @param delta [Numeric, Array<Numeric>, Pattern<Numeric>] event delta
|
64
64
|
# @param metadata [Hash]
|
65
65
|
# @yield [yielder, delta] yielder and event delta
|
@@ -345,7 +345,7 @@ module Xi
|
|
345
345
|
|
346
346
|
# Returns the first +n+ events from the pattern, starting from +cycle+
|
347
347
|
#
|
348
|
-
# @param n [
|
348
|
+
# @param n [Integer]
|
349
349
|
# @param cycle [Numeric]
|
350
350
|
# @return [Array] values
|
351
351
|
#
|
@@ -380,7 +380,7 @@ module Xi
|
|
380
380
|
#
|
381
381
|
# @see #take
|
382
382
|
#
|
383
|
-
# @param n [
|
383
|
+
# @param n [Integer]
|
384
384
|
# @param args same arguments as {#take}
|
385
385
|
# @return [Object, Array]
|
386
386
|
#
|
@@ -420,7 +420,7 @@ module Xi
|
|
420
420
|
# pattern size is assumed to be 1, so iteration size depends on delta
|
421
421
|
# values.
|
422
422
|
#
|
423
|
-
# @return [
|
423
|
+
# @return [Integer]
|
424
424
|
#
|
425
425
|
def iteration_size
|
426
426
|
finite? ? delta_size.lcm(@size) : delta_size
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'xi/stream'
|
2
|
+
require 'xi/osc'
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module Xi::Supercollider
|
6
|
+
class Stream < Xi::Stream
|
7
|
+
include Xi::OSC
|
8
|
+
|
9
|
+
MAX_NODE_ID = 10000
|
10
|
+
DEFAULT_PARAMS = {
|
11
|
+
out: 0,
|
12
|
+
amp: 1.0,
|
13
|
+
pan: 0.0,
|
14
|
+
vel: 127,
|
15
|
+
}
|
16
|
+
|
17
|
+
def initialize(name, clock, server: 'localhost', port: 57110, base_node_id: 2000, **opts)
|
18
|
+
super
|
19
|
+
|
20
|
+
@base_node_id = base_node_id
|
21
|
+
@playing_synths = [].to_set
|
22
|
+
at_exit { free_playing_synths }
|
23
|
+
end
|
24
|
+
|
25
|
+
def set(params)
|
26
|
+
super(gate: params[:gate] || :freq, **params)
|
27
|
+
end
|
28
|
+
|
29
|
+
def stop
|
30
|
+
@mutex.synchronize do
|
31
|
+
@playing_synths.each do |so_id|
|
32
|
+
n_set(node_id(so_id), gate: 0)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
super
|
36
|
+
end
|
37
|
+
|
38
|
+
def free_playing_synths
|
39
|
+
n_free(*@playing_synths.map { |so_id| node_id(so_id) })
|
40
|
+
end
|
41
|
+
|
42
|
+
def node_id(so_id)
|
43
|
+
(@base_node_id + so_id) % MAX_NODE_ID
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def transform_state
|
49
|
+
super
|
50
|
+
|
51
|
+
@state = DEFAULT_PARAMS.merge(@state)
|
52
|
+
|
53
|
+
if changed_param?(:db) && !changed_param?(:amp)
|
54
|
+
@state[:amp] = @state[:db].db_to_amp
|
55
|
+
@changed_params << :amp
|
56
|
+
end
|
57
|
+
|
58
|
+
if changed_param?(:midinote) && !changed_param?(:freq)
|
59
|
+
@state[:freq] = Array(@state[:midinote]).map(&:midi_to_cps)
|
60
|
+
@changed_params << :freq
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def do_gate_on_change(changes)
|
65
|
+
debug "Gate on change: #{changes}"
|
66
|
+
|
67
|
+
name = @state[:s] || :default
|
68
|
+
state_params = @state.reject { |k, _| %i(s).include?(k) }
|
69
|
+
|
70
|
+
freq = Array(state_params[:freq])
|
71
|
+
|
72
|
+
changes.each do |change|
|
73
|
+
at = Time.at(change.fetch(:at))
|
74
|
+
|
75
|
+
change.fetch(:so_ids).each.with_index do |so_id, i|
|
76
|
+
freq_i = freq.size > 0 ? freq[i % freq.size] : nil
|
77
|
+
|
78
|
+
s_new(name, node_id(so_id), **state_params, freq: freq_i, at: at)
|
79
|
+
@playing_synths << so_id
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def do_gate_off_change(changes)
|
85
|
+
debug "Gate off change: #{changes}"
|
86
|
+
|
87
|
+
changes.each do |change|
|
88
|
+
at = Time.at(change.fetch(:at))
|
89
|
+
|
90
|
+
change.fetch(:so_ids).each do |so_id|
|
91
|
+
n_set(node_id(so_id), gate: 0, at: at)
|
92
|
+
@playing_synths.delete(so_id)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def do_state_change
|
98
|
+
debug "State change: #{changed_state}"
|
99
|
+
@playing_synths.each do |so_id|
|
100
|
+
n_set(node_id(so_id), **changed_state)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def n_set(id, at: Time.now, **args)
|
105
|
+
send_bundle('/n_set', id, *osc_args(args), at: at)
|
106
|
+
end
|
107
|
+
|
108
|
+
def s_new(name, id, add_action: 0, target_id: 1, at: Time.now, **args)
|
109
|
+
send_bundle('/s_new', name.to_s, id.to_i, add_action.to_i,
|
110
|
+
target_id.to_i, *osc_args(args), at: at)
|
111
|
+
end
|
112
|
+
|
113
|
+
def n_free(*ids, at: Time.now)
|
114
|
+
send_bundle('/n_free', *ids, at: at)
|
115
|
+
end
|
116
|
+
|
117
|
+
def osc_args(**args)
|
118
|
+
args.map { |k, v| [k.to_s, coerce_osc_value(v)] }.flatten(1)
|
119
|
+
end
|
120
|
+
|
121
|
+
def coerce_osc_value(value)
|
122
|
+
v = Array(value).first
|
123
|
+
v = v.to_f if v.is_a?(Rational)
|
124
|
+
v = v.to_i if !v.is_a?(Float) && !v.is_a?(String) && !v.is_a?(Symbol)
|
125
|
+
v
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/lib/xi/version.rb
CHANGED
data/synthdefs/other.scd
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
(
|
2
|
+
SynthDef(\kick, { |out=0, amp=1, freq=70, attack=0.001, xstart=1, xend=0.25, xdur=0.05, release=0.15, pan=0.5|
|
3
|
+
var sig = SinOsc.ar(freq * XLine.ar(xstart, xend, xdur));
|
4
|
+
var env = EnvGen.ar(Env.perc(attack, release, 1, -4), doneAction: 2);
|
5
|
+
sig = Pan2.ar(sig, pan) * env;
|
6
|
+
sig = (sig * 5).tanh;
|
7
|
+
OffsetOut.ar(out, Pan2.ar(sig * env, pan, amp * 0.25));
|
8
|
+
}).add;
|
9
|
+
|
10
|
+
SynthDef(\snare, { |out=0, amp=1, freq=1000, freq2=180, attack=0.01, release=0.2, pan=0|
|
11
|
+
var snd1 = WhiteNoise.ar(amp);
|
12
|
+
var snd2 = SinOsc.ar(freq2, 0, amp);
|
13
|
+
var env = Env.perc(attack, release).kr(doneAction: 2);
|
14
|
+
var sum = RHPF.ar(snd1 * env, 2500) + LPF.ar(snd2 * env, 1500);
|
15
|
+
OffsetOut.ar(out, Pan2.ar(sum, pan, amp * 0.1))
|
16
|
+
}).add;
|
17
|
+
|
18
|
+
SynthDef(\bassy, { |out=0, amp=1, freq=440, hctf=1000, lctf=5000, rq=0.5, attack=0.001, release=1, mul=1, pan=0.5|
|
19
|
+
var sig = Saw.ar(freq);
|
20
|
+
var env = EnvGen.ar(Env.perc(attack, release), doneAction: 2);
|
21
|
+
sig = mul * BHiPass.ar(RLPF.ar(sig, lctf * env, rq), hctf, rq);
|
22
|
+
OffsetOut.ar(out, Pan2.ar(sig * env, pan, amp * 0.1))
|
23
|
+
}).add;
|
24
|
+
|
25
|
+
SynthDef(\sin, { |out, amp=1, attack=0.001, release=1, sustain=1, pan=0, accelerate=0, freq=440, detune=0.1|
|
26
|
+
var env = EnvGen.ar(Env.perc(attack, release, 1, -4), timeScale: sustain / 2, doneAction: 2);
|
27
|
+
var sound = SinOsc.ar([freq, freq+detune] * Line.kr(1,1+accelerate, sustain));
|
28
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan, amp));
|
29
|
+
}).add;
|
30
|
+
|
31
|
+
SynthDef(\fm, { |out, amp=1, attack=0.001, sustain=1, pan=0, accelerate=0, freq=440, carPartial=1, modPartial=1, index=3, mul=0.1, detune=0.1|
|
32
|
+
var env = EnvGen.ar(Env.perc(attack, 0.999, 1, -3), timeScale: sustain / 2, doneAction: 2);
|
33
|
+
var mod = SinOsc.ar(freq * modPartial * Line.kr(1,1+accelerate, sustain), 0, freq * index * LFNoise1.kr(5.reciprocal).abs);
|
34
|
+
var car = SinOsc.ar(([freq, freq+detune] * carPartial) + mod, 0, mul);
|
35
|
+
OffsetOut.ar(out, Pan2.ar(car * env, pan, amp));
|
36
|
+
}).add;
|
37
|
+
|
38
|
+
SynthDef(\saw, {|out, amp=1, attack=0.001, sustain=1, pan=0, accelerate=0, freq=440, detune=0.1|
|
39
|
+
var env = EnvGen.ar(Env.perc(attack, 0.999, 1, -4), timeScale: sustain / 2, doneAction: 2);
|
40
|
+
var sound = Saw.ar([freq, freq + detune] * Line.kr(1, 1 + accelerate, sustain));
|
41
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan, amp * 0.1));
|
42
|
+
}).add;
|
43
|
+
)
|
@@ -0,0 +1,322 @@
|
|
1
|
+
//
|
2
|
+
// The following synth definitions were taken from Superdirt almost as is.
|
3
|
+
// Original file at https://github.com/musikinformatik/SuperDirt/blob/bb1536329896e6e211c3bafee7befb06d06fc856/library/default-synths-extra.scd
|
4
|
+
//
|
5
|
+
// Source code included in this file is licensed under GPL v2.
|
6
|
+
// Please refer to LICENSE file at
|
7
|
+
// https://github.com/musikinformatik/SuperDirt/blob/master/LICENSE
|
8
|
+
//
|
9
|
+
|
10
|
+
// Physical modeling of a vibrating string, using a delay line (CombL) excited
|
11
|
+
// by an intial pulse (Impulse). To make it a bit richer, I've combined two
|
12
|
+
// slightly detuned delay lines.
|
13
|
+
//
|
14
|
+
// "accelerate" is used for a pitch glide
|
15
|
+
// "sustain" changes the envelope timescale
|
16
|
+
(
|
17
|
+
SynthDef(\smandolin, { |out, amp=1, sustain=1, pan=0, accelerate=0, freq=440, detune=0.2|
|
18
|
+
var env = EnvGen.ar(Env.linen(0.002, 0.996, 0.002, 1,-3), timeScale: sustain, doneAction: 2);
|
19
|
+
var sound = Decay.ar(Impulse.ar(0,0,0.1), 0.1 * (freq.cpsmidi) / 69) * WhiteNoise.ar;
|
20
|
+
var pitch = freq * Line.kr(1, 1 + accelerate, sustain);
|
21
|
+
sound = CombL.ar(sound, 0.05, pitch.reciprocal * (1 - (detune/100)), sustain)
|
22
|
+
+ CombL.ar(sound, 0.05, pitch.reciprocal * (1 + (detune/100)), sustain);
|
23
|
+
OffsetOut.ar(out, Pan2.ar(sound * env * amp, pan))
|
24
|
+
}).add
|
25
|
+
);
|
26
|
+
|
27
|
+
// An example of additive synthesis, building up a gong-like noise from a sum
|
28
|
+
// of sine-wave harmonics. Notice how the envelope timescale and amplitude can
|
29
|
+
// be scaled as a function of the harmonic frequency.
|
30
|
+
// "voice" provides something like a tone knob
|
31
|
+
// "decay" adjusts how the harmonics decay as in the other SynthDefs
|
32
|
+
// "sustain" affects the overall envelope timescale
|
33
|
+
// "accelerate" for pitch glide
|
34
|
+
(
|
35
|
+
SynthDef(\sgong, { |out, amp=1, sustain=1, pan=0, accelerate=0, freq=440, voice=0, decay=1|
|
36
|
+
// lowest modes for clamped circular plate
|
37
|
+
var freqlist = [1.000, 2.081, 3.414, 3.893, 4.995, 5.954, 6.819, 8.280, 8.722, 8.882, 10.868, 11.180, 11.754, 13.710, 13.715, 15.057, 15.484, 16.469, 16.817, 18.628] ** 1.0;
|
38
|
+
var tscale = 100.0 / freq / (freqlist ** (2 - clip(decay, 0, 2)));
|
39
|
+
var ascale =freqlist ** clip(voice,0,4);
|
40
|
+
var sound = Mix.arFill(15, { arg i;
|
41
|
+
EnvGen.ar(Env.perc(0.01 * tscale[i], 0.5 * tscale[i], 0.2 * ascale[i]), timeScale: sustain * 5)
|
42
|
+
* SinOsc.ar(freq * freqlist[i] * Line.kr(1, 1 + accelerate, sustain))
|
43
|
+
});
|
44
|
+
OffsetOut.ar(out, Pan2.ar(sound * amp / 15, pan))
|
45
|
+
}).add
|
46
|
+
);
|
47
|
+
|
48
|
+
// Hooking into a nice synth piano already in Supercollider.
|
49
|
+
//
|
50
|
+
// Uses the "velocity" parameter to affect how hard the keys are pressed
|
51
|
+
// "sustain" controls envelope and decay time.
|
52
|
+
(
|
53
|
+
SynthDef(\spiano, { |out, amp=1, sustain=1, pan=0, velocity=1, detune=0.1, muffle=1, stereo=0.2, freq=440|
|
54
|
+
var env = EnvGen.ar(Env.linen(0.002, 0.996, 0.002, 1, -3), timeScale: sustain, doneAction: 2);
|
55
|
+
// the +0.01 to freq is because of edge case rounding internal to the MdaPiano synth
|
56
|
+
var sound = MdaPiano.ar(freq + 0.01, vel: velocity * 100, hard: 0.8 * velocity, decay: 0.1 * sustain,
|
57
|
+
tune: 0.5, random: 0.05, stretch: detune, muffle: 0.8 * muffle, stereo: stereo);
|
58
|
+
OffsetOut.ar(out, Pan2.ar(sound * env * amp * 0.35, pan))
|
59
|
+
}).add
|
60
|
+
);
|
61
|
+
|
62
|
+
// Waveguide mesh, hexagonal drum-like membrane
|
63
|
+
(
|
64
|
+
SynthDef(\shex, { |out, speed=1, sustain=1, pan=0, freq=440, accelerate=0|
|
65
|
+
var env = EnvGen.ar(Env.linen(0.02, 0.96, 0.02, 1,-3), timeScale: sustain, doneAction: 2);
|
66
|
+
var tension = 0.05 * freq / 400 * Line.kr(1, accelerate + 1, sustain);
|
67
|
+
var loss = 1.0 - (0.01 * speed / freq);
|
68
|
+
var sound = MembraneHexagon.ar(Decay.ar(Impulse.ar(0, 0, 1), 0.01), tension, loss);
|
69
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan))
|
70
|
+
}).add
|
71
|
+
);
|
72
|
+
|
73
|
+
// Kick Drum using Rumble-San's implementation as a starting point
|
74
|
+
// http://blog.rumblesan.com/post/53271713518/drum-sounds-in-supercollider-part-1
|
75
|
+
//
|
76
|
+
// "n" controls the kick frequency in a nonstandard way
|
77
|
+
// "sustain" affects overall envelope timescale
|
78
|
+
// "accelerate" sweeps the click filter freq
|
79
|
+
// "pitch1" affects the click frequency
|
80
|
+
// "decay" changes the click duration relative to the overall timescale
|
81
|
+
(
|
82
|
+
SynthDef(\skick, { |out, sustain=1, pan=0, accelerate=0, n=60, pitch1=1, decay=1, amp=1|
|
83
|
+
var env, sound, dur, clickdur;
|
84
|
+
env = EnvGen.ar(Env.linen(0.01, 0, 0.5, 1, -3), timeScale: sustain, doneAction: 2);
|
85
|
+
sound = SinOsc.ar((n - 25.5).midicps);
|
86
|
+
clickdur = 0.02 * sustain * decay;
|
87
|
+
sound = sound + (LPF.ar(WhiteNoise.ar(1), 1500 * pitch1 * Line.kr(1, 1 + accelerate, clickdur))
|
88
|
+
* Line.ar(1, 0, clickdur));
|
89
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan, amp))
|
90
|
+
}).add
|
91
|
+
);
|
92
|
+
|
93
|
+
// A vaguely 808-ish kick drum
|
94
|
+
//
|
95
|
+
// "n" controls the chirp frequency
|
96
|
+
// "sustain" the overall timescale
|
97
|
+
// "speed" the filter sweep speed
|
98
|
+
// "voice" the sinewave feedback
|
99
|
+
(
|
100
|
+
SynthDef(\s808, { |out, speed=1, sustain=1, pan=0, voice=0, n=60, amp=1|
|
101
|
+
var env, sound, freq;
|
102
|
+
n = ((n>0)*n) + ((n<1)*3);
|
103
|
+
freq = (n*10).midicps;
|
104
|
+
env = EnvGen.ar(Env.linen(0.01, 0, 1, 1, -3), timeScale:sustain, doneAction:2);
|
105
|
+
sound = LPF.ar(SinOscFB.ar(XLine.ar(freq.expexp(10, 2000, 1000, 8000), freq, 0.025/speed), voice), 9000);
|
106
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan, amp))
|
107
|
+
}).add
|
108
|
+
);
|
109
|
+
|
110
|
+
// Hi-hat using Rumble-San's implementation as a starting point
|
111
|
+
// http://blog.rumblesan.com/post/53271713518/drum-sounds-in-supercollider-part-1
|
112
|
+
//
|
113
|
+
// "n" using it in a weird way to provide some variation on the frequency
|
114
|
+
// "sustain" affects the overall envelope rate,
|
115
|
+
// "accelerate" sweeps the filter
|
116
|
+
(
|
117
|
+
SynthDef(\shat, {|out, sustain=1, pan=0, accelerate=0, n=60, amp=1, freq=2000|
|
118
|
+
var env, sound, accel, frq;
|
119
|
+
env = EnvGen.ar(Env.linen(0.01, 0, 0.3, 1, -3), timeScale: sustain, doneAction:2);
|
120
|
+
accel = Line.kr(1, 1+accelerate, 0.2*sustain);
|
121
|
+
frq = freq*accel*(n/5 + 1).wrap(0.5,2);
|
122
|
+
sound = HPF.ar(LPF.ar(WhiteNoise.ar(1), 3*frq), frq);
|
123
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan, amp))
|
124
|
+
}).add
|
125
|
+
);
|
126
|
+
|
127
|
+
// Snare drum using Rumble-San's implementation as a starting point
|
128
|
+
// http://blog.rumblesan.com/post/53271713909/drum-sounds-in-supercollider-part-2
|
129
|
+
//
|
130
|
+
// "n" for some variation on frequency
|
131
|
+
// "decay" for scaling noise duration relative to tonal part
|
132
|
+
// "sustain" for overall timescale
|
133
|
+
// "accelerate" for tonal glide
|
134
|
+
(
|
135
|
+
SynthDef(\ssnare, {|out, sustain=1, pan=0, accelerate=0, n=60, decay=1, amp=1|
|
136
|
+
var env, sound, accel;
|
137
|
+
env = EnvGen.ar(Env.linen(0.01, 0, 0.6, 1, -3), timeScale:sustain, doneAction:2);
|
138
|
+
accel = Line.kr(1, 1+accelerate, 0.2);
|
139
|
+
sound = LPF.ar(Pulse.ar(100*accel*(n/5+1).wrap(0.5,2)), Line.ar(1030, 30, 0.2*sustain));
|
140
|
+
sound = sound + (BPF.ar(HPF.ar(WhiteNoise.ar(1), 500), 1500) * Line.ar(1, 0, 0.2*decay));
|
141
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan, amp))
|
142
|
+
}).add
|
143
|
+
);
|
144
|
+
|
145
|
+
// Hand clap using Rumble-San's implementation as a starting point
|
146
|
+
// http://blog.rumblesan.com/post/53271713909/drum-sounds-in-supercollider-part-2
|
147
|
+
//
|
148
|
+
// "delay" controls the echo delay
|
149
|
+
// "speed" will affect the decay time
|
150
|
+
// "n" changes how spread is calculated
|
151
|
+
// "pitch1" will scale the bandpass frequency
|
152
|
+
// "sustain" the overall timescale
|
153
|
+
(
|
154
|
+
SynthDef(\sclap, {|out, speed=1, sustain=1, pan=0, n=60, delay=1, pitch1=1, amp=1|
|
155
|
+
var env, sound;
|
156
|
+
var spr = 0.005 * delay;
|
157
|
+
env = EnvGen.ar(Env.linen(0.01, 0, 0.6, 1, -3), timeScale:sustain, doneAction:2);
|
158
|
+
sound = BPF.ar(LPF.ar(WhiteNoise.ar(1), 7500*pitch1), 1500*pitch1);
|
159
|
+
sound = Mix.arFill(4, {arg i; sound * 0.5 * EnvGen.ar(Env.new([0,0,1,0],[spr*(i**(n.clip(0,5)+1)),0,0.04/speed]))});
|
160
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan, amp))
|
161
|
+
}).add
|
162
|
+
);
|
163
|
+
|
164
|
+
// A controllable synth siren, defaults to 1 second, draw it out with "sustain"
|
165
|
+
(
|
166
|
+
SynthDef(\ssiren, {|out, sustain=1, pan=0, freq=440, amp=1|
|
167
|
+
var env, sound;
|
168
|
+
env = EnvGen.ar(Env.linen(0.05, 0.9, 0.05, 1, -2), timeScale:sustain, doneAction:2);
|
169
|
+
sound = VarSaw.ar(freq * (1.0 + EnvGen.kr(Env.linen(0.25,0.5,0.25,3,0), timeScale:sustain, doneAction:2)),
|
170
|
+
0, width:Line.kr(0.05,1,sustain));
|
171
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan, amp))
|
172
|
+
}).add
|
173
|
+
);
|
174
|
+
|
175
|
+
// The next four synths respond to the following parameters in addition to
|
176
|
+
// gain, pan, n, and all the "effect" parameters (including attack, hold, and
|
177
|
+
// release). Default values in parentheses.
|
178
|
+
//
|
179
|
+
// sustain - scales overall duration
|
180
|
+
// decay(0) - amount of decay after initial attack
|
181
|
+
// accelerate(0) - pitch glide
|
182
|
+
// semitone(12) - how far off in pitch the secondary oscillator is (need not be integer)
|
183
|
+
// pitch1(1) - filter frequency scaling multiplier, the frequency itself follows the pitch set by "n"
|
184
|
+
// speed(1)- LFO rate
|
185
|
+
// lfo(1) - how much the LFO affects the filter frequency
|
186
|
+
// resonance(0.2) - filter resonance
|
187
|
+
// voice(0.5) - depends on the individual synth
|
188
|
+
|
189
|
+
// A moog-inspired square-wave synth; variable-width pulses with filter
|
190
|
+
// frequency modulated by an LFO
|
191
|
+
//
|
192
|
+
// "voice" controls the pulse width (exactly zero or one will make no sound)
|
193
|
+
(
|
194
|
+
SynthDef(\ssquare, {|out, speed=1, decay=0, sustain=1, pan=0, accelerate=0, freq=440,
|
195
|
+
voice=0.5, semitone=12, resonance=0.2, lfo=1, pitch1=1, amp=1|
|
196
|
+
var env = EnvGen.ar(Env.pairs([[0,0],[0.05,1],[0.2,1-decay],[0.95,1-decay],[1,0]], -3), timeScale:sustain, doneAction:2);
|
197
|
+
var basefreq = freq* Line.kr(1, 1+accelerate, sustain);
|
198
|
+
var basefreq2 = basefreq / (2**(semitone/12));
|
199
|
+
var lfof1 = min(basefreq*10*pitch1, 22000);
|
200
|
+
var lfof2 = min(lfof1 * (lfo + 1), 22000);
|
201
|
+
var sound = (0.7 * Pulse.ar(basefreq, voice)) + (0.3 * Pulse.ar(basefreq2, voice));
|
202
|
+
sound = MoogFF.ar(
|
203
|
+
sound,
|
204
|
+
SinOsc.ar(basefreq/64*speed, 0).range(lfof1,lfof2),
|
205
|
+
resonance*4);
|
206
|
+
sound = sound.tanh * 2;
|
207
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan, amp));
|
208
|
+
}).add
|
209
|
+
);
|
210
|
+
|
211
|
+
// A moog-inspired sawtooth synth; slightly detuned saws with triangle
|
212
|
+
// harmonics, filter frequency modulated by LFO
|
213
|
+
//
|
214
|
+
// "voice" controls a relative phase and detune amount
|
215
|
+
(
|
216
|
+
SynthDef(\ssaw, {|out, speed=1, decay=0, sustain=1, pan=0, accelerate=0, freq=440,
|
217
|
+
voice=0.5, semitone=12, resonance=0.2, lfo=1, pitch1=1, amp=1|
|
218
|
+
var env = EnvGen.ar(Env.pairs([[0,0],[0.05,1],[0.2,1-decay],[0.95,1-decay],[1,0]], -3), timeScale:sustain, doneAction:2);
|
219
|
+
var basefreq = freq * Line.kr(1, 1+accelerate, sustain);
|
220
|
+
var basefreq2 = basefreq * (2**(semitone/12));
|
221
|
+
var lfof1 = min(basefreq*10*pitch1, 22000);
|
222
|
+
var lfof2 = min(lfof1 * (lfo + 1), 22000);
|
223
|
+
var sound = MoogFF.ar(
|
224
|
+
(0.5 * Mix.arFill(3, {|i| SawDPW.ar(basefreq * ((i-1)*voice/50+1), 0)})) + (0.5 * LFTri.ar(basefreq2, voice)),
|
225
|
+
LFTri.ar(basefreq/64*speed, 0.5).range(lfof1,lfof2),
|
226
|
+
resonance*4);
|
227
|
+
sound = sound.tanh*2;
|
228
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan, amp));
|
229
|
+
}).add
|
230
|
+
);
|
231
|
+
|
232
|
+
// A moog-inspired PWM synth; pulses multiplied by phase-shifted pulses, double
|
233
|
+
// filtering with an envelope on the second.
|
234
|
+
//
|
235
|
+
// "voice" controls the phase shift rate
|
236
|
+
(
|
237
|
+
SynthDef(\spwm, {|out, speed=1, decay=0, sustain=1, pan=0, accelerate=0, freq=440,
|
238
|
+
voice=0.5, semitone=12, resonance=0.2, lfo=1, pitch1=1, amp=1|
|
239
|
+
var env = EnvGen.ar(Env.pairs([[0,0],[0.05,1],[0.2,1-decay],[0.95,1-decay],[1,0]], -3), timeScale:sustain, doneAction:2);
|
240
|
+
var env2 = EnvGen.ar(Env.pairs([[0,0.1],[0.1,1],[0.4,0.5],[0.9,0.2],[1,0.2]], -3), timeScale:sustain/speed);
|
241
|
+
var basefreq = freq * Line.kr(1, 1+accelerate, sustain);
|
242
|
+
var basefreq2 = basefreq / (2**(semitone/12));
|
243
|
+
var lfof1 = min(basefreq*10*pitch1, 22000);
|
244
|
+
var lfof2 = min(lfof1 * (lfo + 1), 22000);
|
245
|
+
var sound = 0.7 * PulseDPW.ar(basefreq) * DelayC.ar(PulseDPW.ar(basefreq), 0.2, Line.kr(0,voice,sustain)/basefreq);
|
246
|
+
sound = 0.3 * PulseDPW.ar(basefreq2) * DelayC.ar(PulseDPW.ar(basefreq2), 0.2, Line.kr(0.1,0.1+voice,sustain)/basefreq) + sound;
|
247
|
+
sound = MoogFF.ar(sound, SinOsc.ar(basefreq/32*speed, 0).range(lfof1,lfof2), resonance*4);
|
248
|
+
sound = MoogFF.ar(sound, min(env2*lfof2*1.1, 22000), 3);
|
249
|
+
sound = sound.tanh*5;
|
250
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan, amp));
|
251
|
+
}).add
|
252
|
+
);
|
253
|
+
|
254
|
+
// This synth is inherently stereo, so handles the "pan" parameter itself and
|
255
|
+
// tells SuperDirt not to mix down to mono.
|
256
|
+
//
|
257
|
+
// "voice" scales the comparator frequencies, higher values will sound "breathier"
|
258
|
+
(
|
259
|
+
SynthDef(\scomparator, {|out, speed=1, decay=0, sustain=1, pan=0, accelerate=0, freq=440,
|
260
|
+
voice=0.5, resonance=0.5, lfo=1, pitch1=1, amp=1|
|
261
|
+
var env = EnvGen.ar(Env.pairs([[0,0],[0.05,1],[0.2,1-decay],[0.95,1-decay],[1,0]], -3), timeScale:sustain, doneAction:2);
|
262
|
+
var basefreq = freq * Line.kr(1, 1+accelerate, sustain);
|
263
|
+
var sound = VarSaw.ar(basefreq, 0, Line.ar(0,1,sustain));
|
264
|
+
var freqlist =[ 1.000, 2.188, 5.091, 8.529, 8.950, 9.305, 13.746, 14.653, 19.462, 22.003, 24.888, 25.991,
|
265
|
+
26.085, 30.509, 33.608, 35.081, 40.125, 42.023, 46.527, 49.481]**(voice/5);
|
266
|
+
sound = Splay.arFill(16, {|i| sound > LFTri.ar(freqlist[i])}, 1);
|
267
|
+
sound = MoogFF.ar(
|
268
|
+
sound,
|
269
|
+
pitch1 * 4 * basefreq + SinOsc.ar(basefreq/64*speed, 0, lfo*basefreq/2) + LFNoise2.ar(1,lfo*basefreq),
|
270
|
+
LFNoise2.ar(0,0.1,4*resonance));
|
271
|
+
sound = 0.5 * Balance2.ar(sound[0], sound[1], pan*2-1);
|
272
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, 0.5, amp));
|
273
|
+
}).add
|
274
|
+
);
|
275
|
+
|
276
|
+
// Uses the Atari ST emulation UGen with 3 oscillators
|
277
|
+
//
|
278
|
+
// "slide" is for a linear frequency glide that will repeat "speed" times (can
|
279
|
+
// be fractional or negative).
|
280
|
+
// "accelerate" is for an overall glide
|
281
|
+
// "pitch2" and "pitch3" control the ratio of harmonics
|
282
|
+
// "voice" causes variations in the levels of the 3 oscillators
|
283
|
+
(
|
284
|
+
SynthDef(\schip, {|out, sustain=1, pan=0, freq=440, speed=1, slide=0, pitch2=2, pitch3=3, accelerate=0, voice=0, amp=1|
|
285
|
+
var env, basefreq, sound, va, vb, vc;
|
286
|
+
env = EnvGen.ar(Env.linen(0.01, 0.98, 0.01,1,-1), timeScale:sustain, doneAction:2);
|
287
|
+
basefreq = freq + wrap2(slide * 100 * Line.kr(-1,1+(2*speed-2),sustain), slide * 100);
|
288
|
+
basefreq = basefreq * Line.kr(1, accelerate+1, sustain);
|
289
|
+
va = (voice < 0.5) * 15;
|
290
|
+
vb = ((2*voice) % 1 < 0.5) * 15;
|
291
|
+
vc = ((4*voice) % 1 < 0.5) * 15;
|
292
|
+
sound= AY.ar( AY.freqtotone(basefreq), AY.freqtotone(pitch2*basefreq), AY.freqtotone(pitch3*basefreq),
|
293
|
+
vola:va, volb:vb, volc:vc)/2;
|
294
|
+
sound = tanh(sound)*2;
|
295
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan, amp));
|
296
|
+
}).add
|
297
|
+
);
|
298
|
+
|
299
|
+
// Digital noise in several flavors with a bandpass filter
|
300
|
+
//
|
301
|
+
// "voice" at 0 is a digital noise for which "n" controls rate, at 1 is
|
302
|
+
// Brown+White noise for which "n" controls knee frequency.
|
303
|
+
// "accelerate" causes glide in n, "speed" will cause it to repeat
|
304
|
+
// "pitch1" scales the bandpass frequency (which tracks "n")
|
305
|
+
// "slide" works like accelerate on the bandpass
|
306
|
+
// "resonance" is the filter resonance
|
307
|
+
(
|
308
|
+
SynthDef(\snoise, {|out, sustain=1, pan=0, freq=440, accelerate=0, slide=0, pitch1=1, speed=1, resonance=0, voice=0, amp=1|
|
309
|
+
var env, basefreq, sound, ffreq, acc;
|
310
|
+
env = EnvGen.ar(Env.linen(0.01, 0.98, 0.01,1,-1), timeScale:sustain, doneAction:2);
|
311
|
+
acc = accelerate * freq * 4;
|
312
|
+
basefreq = freq * 8 + wrap2(acc* Line.kr(-1,1+(2*speed-2), sustain), acc);
|
313
|
+
ffreq = basefreq*5*pitch1* Line.kr(1,1+slide, sustain);
|
314
|
+
ffreq = clip(ffreq, 60,20000);
|
315
|
+
sound = XFade2.ar( LFDNoise0.ar(basefreq.min(22000), 0.5),
|
316
|
+
XFade2.ar(BrownNoise.ar(0.5), WhiteNoise.ar(0.5), basefreq.cpsmidi/127),
|
317
|
+
2*voice-1);
|
318
|
+
sound = HPF.ar(BMoog.ar(sound, ffreq, resonance, 3), 20);
|
319
|
+
sound = clip(sound, -1,1) * 0.3;
|
320
|
+
OffsetOut.ar(out, Pan2.ar(sound * env, pan, amp));
|
321
|
+
}).add
|
322
|
+
);
|
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.
|
4
|
+
version: 0.2.0
|
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:
|
11
|
+
date: 2019-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -134,13 +134,15 @@ files:
|
|
134
134
|
- lib/xi/core_ext/array.rb
|
135
135
|
- lib/xi/core_ext/enumerable.rb
|
136
136
|
- lib/xi/core_ext/enumerator.rb
|
137
|
-
- lib/xi/core_ext/
|
137
|
+
- lib/xi/core_ext/integer.rb
|
138
138
|
- lib/xi/core_ext/numeric.rb
|
139
139
|
- lib/xi/core_ext/object.rb
|
140
140
|
- lib/xi/core_ext/scalar.rb
|
141
141
|
- lib/xi/core_ext/string.rb
|
142
142
|
- lib/xi/error_log.rb
|
143
143
|
- lib/xi/logger.rb
|
144
|
+
- lib/xi/osc.rb
|
145
|
+
- lib/xi/osc/version.rb
|
144
146
|
- lib/xi/pattern.rb
|
145
147
|
- lib/xi/pattern/generators.rb
|
146
148
|
- lib/xi/pattern/transforms.rb
|
@@ -148,8 +150,13 @@ files:
|
|
148
150
|
- lib/xi/scale.rb
|
149
151
|
- lib/xi/step_sequencer.rb
|
150
152
|
- lib/xi/stream.rb
|
153
|
+
- lib/xi/supercollider.rb
|
154
|
+
- lib/xi/supercollider/stream.rb
|
155
|
+
- lib/xi/supercollider/version.rb
|
151
156
|
- lib/xi/tidal_clock.rb
|
152
157
|
- lib/xi/version.rb
|
158
|
+
- synthdefs/other.scd
|
159
|
+
- synthdefs/superdirt.scd
|
153
160
|
- xi.gemspec
|
154
161
|
homepage: https://github.com/xi-livecode/xi
|
155
162
|
licenses:
|
@@ -170,8 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
170
177
|
- !ruby/object:Gem::Version
|
171
178
|
version: '0'
|
172
179
|
requirements: []
|
173
|
-
|
174
|
-
rubygems_version: 2.7.6
|
180
|
+
rubygems_version: 3.0.3
|
175
181
|
signing_key:
|
176
182
|
specification_version: 4
|
177
183
|
summary: Musical pattern language for livecoding
|
data/lib/xi/core_ext/fixnum.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
module Xi::CoreExt
|
2
|
-
module Fixnum
|
3
|
-
def /(o)
|
4
|
-
super(o.to_r)
|
5
|
-
end
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4')
|
10
|
-
class Fixnum
|
11
|
-
prepend Xi::CoreExt::Fixnum
|
12
|
-
end
|
13
|
-
else
|
14
|
-
class Integer
|
15
|
-
prepend Xi::CoreExt::Fixnum
|
16
|
-
end
|
17
|
-
end
|