ruck-ugen 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/README +31 -0
- data/Rakefile +24 -0
- data/VERSION +1 -0
- data/bin/ruck_ugen +30 -0
- data/examples/ex01.rb +24 -0
- data/examples/ex02.rb +2 -0
- data/examples/ex03.rb +8 -0
- data/examples/ex04.rb +14 -0
- data/examples/ex05.rb +9 -0
- data/examples/ex06.rb +10 -0
- data/examples/ex07.rb +35 -0
- data/examples/ex08.rb +28 -0
- data/examples/ex09.rb +26 -0
- data/examples/ex10.rb +10 -0
- data/examples/ex11.rb +9 -0
- data/lib/ruck/misc/linkage.rb +52 -0
- data/lib/ruck/misc/riff.rb +101 -0
- data/lib/ruck/ugen/basic.rb +235 -0
- data/lib/ruck/ugen/oscillators.rb +114 -0
- data/lib/ruck/ugen/time_helpers.rb +31 -0
- data/lib/ruck/ugen/ugen.rb +229 -0
- data/lib/ruck/ugen/wav.rb +187 -0
- data/lib/ruck/ugen.rb +7 -0
- data/ruck-ugen.gemspec +85 -0
- data/test/bench.rb +57 -0
- metadata +110 -0
@@ -0,0 +1,187 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), "..", "misc", "riff")
|
3
|
+
|
4
|
+
module Ruck
|
5
|
+
module UGen
|
6
|
+
module Generators
|
7
|
+
|
8
|
+
# saves all incoming samples in memory to export to disk later
|
9
|
+
# outputs 0.0 samples
|
10
|
+
class WavOut
|
11
|
+
include UGenBase
|
12
|
+
include Source
|
13
|
+
include MultiChannelTarget
|
14
|
+
|
15
|
+
attr_reader :filename
|
16
|
+
|
17
|
+
def initialize(attrs = {})
|
18
|
+
require_attrs attrs, [:filename]
|
19
|
+
@filename = attrs.delete(:filename)
|
20
|
+
@num_channels = attrs.delete(:num_channels) || 1
|
21
|
+
@bits_per_sample = attrs.delete(:bits_per_sample) || 16
|
22
|
+
parse_attrs attrs
|
23
|
+
|
24
|
+
@in_channels = (1..@num_channels).map { InChannel.new }
|
25
|
+
|
26
|
+
@sample_rate = SAMPLE_RATE
|
27
|
+
@samples = (1..@num_channels).map { [] }
|
28
|
+
@ins = []
|
29
|
+
@last = 0.0
|
30
|
+
|
31
|
+
# TODO: this is necessary, but if UGen graph were explicitly
|
32
|
+
# destructed, that would be nice.
|
33
|
+
at_exit { save }
|
34
|
+
end
|
35
|
+
|
36
|
+
def next(now)
|
37
|
+
return @last if @now == now
|
38
|
+
@now = now
|
39
|
+
@samples << @in_channels.map { |chan| chan.next now }
|
40
|
+
@last
|
41
|
+
end
|
42
|
+
|
43
|
+
def save
|
44
|
+
LOG.info "Saving WAV to #{@filename}..."
|
45
|
+
File.open(@filename, "wb") { |f| f.write encode }
|
46
|
+
end
|
47
|
+
|
48
|
+
def attr_names
|
49
|
+
[:filename]
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def encode
|
55
|
+
chunk("RIFF") do |riff|
|
56
|
+
riff << ascii("WAVE")
|
57
|
+
riff << chunk("fmt ") do |fmt|
|
58
|
+
fmt << short(1) # format = 1: PCM (no compression)
|
59
|
+
fmt << short(@num_channels)
|
60
|
+
fmt << int(@sample_rate)
|
61
|
+
fmt << int((@sample_rate * @num_channels * (@bits_per_sample / 8))) # byte-rate
|
62
|
+
fmt << short((@num_channels * @bits_per_sample/8)) # block align
|
63
|
+
fmt << short(@bits_per_sample) # bits/sample
|
64
|
+
end
|
65
|
+
riff << chunk("data") do |data|
|
66
|
+
range = 2 ** (@bits_per_sample - 1)
|
67
|
+
@samples.each do |sample_list|
|
68
|
+
sample_list.each { |sample| data << [sample * range].pack("s1") }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def int(i)
|
75
|
+
[i].pack("i1")
|
76
|
+
end
|
77
|
+
|
78
|
+
def short(s)
|
79
|
+
[s].pack("s1")
|
80
|
+
end
|
81
|
+
|
82
|
+
def ascii(str)
|
83
|
+
str.split("").pack("A1" * str.length)
|
84
|
+
end
|
85
|
+
|
86
|
+
def chunk(type, &block)
|
87
|
+
buf = ""
|
88
|
+
block.call(buf)
|
89
|
+
ascii(type) + int(buf.length) + buf
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
# plays sound stored in a RIFF WAV file
|
95
|
+
class WavIn
|
96
|
+
include UGenBase
|
97
|
+
include MultiChannelSource
|
98
|
+
|
99
|
+
linkable_attr :rate
|
100
|
+
linkable_attr :gain
|
101
|
+
attr_reader :filename
|
102
|
+
|
103
|
+
def initialize(attrs = {})
|
104
|
+
require_attrs attrs, [:filename]
|
105
|
+
@rate = 1.0
|
106
|
+
@gain = 1.0
|
107
|
+
@filename = attrs.delete(:filename)
|
108
|
+
parse_attrs attrs
|
109
|
+
|
110
|
+
@loaded = false
|
111
|
+
@playing = true
|
112
|
+
|
113
|
+
init_wav
|
114
|
+
end
|
115
|
+
|
116
|
+
def init_wav
|
117
|
+
riff = Riff::RiffReader.new(@filename).chunks.first
|
118
|
+
unless riff.type == "RIFF"
|
119
|
+
LOG.error "#{@filename}: Not RIFF!"
|
120
|
+
return
|
121
|
+
end
|
122
|
+
unless riff[0..3] == "WAVE"
|
123
|
+
LOG.error "#{@filename}: Not WAVE!"
|
124
|
+
return
|
125
|
+
end
|
126
|
+
|
127
|
+
riff.data_skip = 4 # skip "WAVE"
|
128
|
+
fmt = riff.chunks.first
|
129
|
+
@wav = riff.chunks.find { |c| c.type == "data" }
|
130
|
+
unless fmt[0..1].unpack("s1").first == 1
|
131
|
+
LOG.error "#{@filename}: Not PCM!"
|
132
|
+
return
|
133
|
+
end
|
134
|
+
|
135
|
+
@num_channels, @sample_rate, @byte_rate,
|
136
|
+
@block_align, @bits_per_sample =
|
137
|
+
fmt[2..15].unpack("s1i1i1s1s1")
|
138
|
+
@range = (2 ** (@bits_per_sample - 1)).to_f
|
139
|
+
|
140
|
+
@out_channels = (0..@num_channels-1).map { |chan| OutChannel.new self, chan }
|
141
|
+
@sample = [0.0] * @num_channels
|
142
|
+
@last = [0.0] * @num_channels
|
143
|
+
@now = [nil] * @num_channels
|
144
|
+
@rate_adjust = @sample_rate / SAMPLE_RATE
|
145
|
+
|
146
|
+
@loaded = true
|
147
|
+
end
|
148
|
+
|
149
|
+
def duration
|
150
|
+
@loaded ? @wav.size / @block_align / @rate_adjust : 0
|
151
|
+
end
|
152
|
+
|
153
|
+
def attr_names
|
154
|
+
[:filename, :rate]
|
155
|
+
end
|
156
|
+
|
157
|
+
def next(now, chan = 0)
|
158
|
+
return @last[chan] if @now[chan] == now
|
159
|
+
@now[chan] = now
|
160
|
+
|
161
|
+
return @last[chan] unless @loaded && @playing
|
162
|
+
|
163
|
+
offset = @sample[chan].to_i * @block_align
|
164
|
+
chan_offset = (chan * @bits_per_sample) / 8
|
165
|
+
|
166
|
+
if offset + @block_align > @wav.size
|
167
|
+
@playing = false
|
168
|
+
return @last[chan]
|
169
|
+
end
|
170
|
+
|
171
|
+
@last[chan] = @wav[offset + chan_offset, @bits_per_sample].unpack("s1").first / @range * gain
|
172
|
+
@sample[chan] += rate * @rate_adjust
|
173
|
+
@last[chan]
|
174
|
+
end
|
175
|
+
|
176
|
+
def play; @playing = true; end
|
177
|
+
def stop; @playing = false; end
|
178
|
+
|
179
|
+
def reset
|
180
|
+
@offset = 0
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
data/lib/ruck/ugen.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), "misc", "linkage")
|
3
|
+
require File.join(File.dirname(__FILE__), "ugen", "ugen")
|
4
|
+
require File.join(File.dirname(__FILE__), "ugen", "basic")
|
5
|
+
require File.join(File.dirname(__FILE__), "ugen", "time_helpers")
|
6
|
+
require File.join(File.dirname(__FILE__), "ugen", "oscillators")
|
7
|
+
require File.join(File.dirname(__FILE__), "ugen", "wav")
|
data/ruck-ugen.gemspec
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{ruck-ugen}
|
8
|
+
s.version = "0.2.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Tom Lieber"]
|
12
|
+
s.date = %q{2010-07-10}
|
13
|
+
s.default_executable = %q{ruck_ugen}
|
14
|
+
s.description = %q{ A ruck shreduler and mini audio unit generator framework inspired by ChucK.
|
15
|
+
Includes library for reading and writing multi-channel WAV files, and some
|
16
|
+
basic audio filters.
|
17
|
+
}
|
18
|
+
s.email = %q{tom@alltom.com}
|
19
|
+
s.executables = ["ruck_ugen"]
|
20
|
+
s.extra_rdoc_files = [
|
21
|
+
"README"
|
22
|
+
]
|
23
|
+
s.files = [
|
24
|
+
".document",
|
25
|
+
".gitignore",
|
26
|
+
"README",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"bin/ruck_ugen",
|
30
|
+
"examples/ex01.rb",
|
31
|
+
"examples/ex02.rb",
|
32
|
+
"examples/ex03.rb",
|
33
|
+
"examples/ex04.rb",
|
34
|
+
"examples/ex05.rb",
|
35
|
+
"examples/ex06.rb",
|
36
|
+
"examples/ex07.rb",
|
37
|
+
"examples/ex08.rb",
|
38
|
+
"examples/ex09.rb",
|
39
|
+
"examples/ex10.rb",
|
40
|
+
"examples/ex11.rb",
|
41
|
+
"lib/ruck/misc/linkage.rb",
|
42
|
+
"lib/ruck/misc/riff.rb",
|
43
|
+
"lib/ruck/ugen.rb",
|
44
|
+
"lib/ruck/ugen/basic.rb",
|
45
|
+
"lib/ruck/ugen/oscillators.rb",
|
46
|
+
"lib/ruck/ugen/time_helpers.rb",
|
47
|
+
"lib/ruck/ugen/ugen.rb",
|
48
|
+
"lib/ruck/ugen/wav.rb",
|
49
|
+
"ruck-ugen.gemspec",
|
50
|
+
"test/bench.rb"
|
51
|
+
]
|
52
|
+
s.homepage = %q{http://github.com/alltom/ruck-ugen}
|
53
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
54
|
+
s.require_paths = ["lib"]
|
55
|
+
s.rubygems_version = %q{1.3.6}
|
56
|
+
s.summary = %q{ruck shreduler + mini audio unit generator framework inspired by ChucK}
|
57
|
+
s.test_files = [
|
58
|
+
"test/bench.rb",
|
59
|
+
"examples/ex01.rb",
|
60
|
+
"examples/ex02.rb",
|
61
|
+
"examples/ex03.rb",
|
62
|
+
"examples/ex04.rb",
|
63
|
+
"examples/ex05.rb",
|
64
|
+
"examples/ex06.rb",
|
65
|
+
"examples/ex07.rb",
|
66
|
+
"examples/ex08.rb",
|
67
|
+
"examples/ex09.rb",
|
68
|
+
"examples/ex10.rb",
|
69
|
+
"examples/ex11.rb"
|
70
|
+
]
|
71
|
+
|
72
|
+
if s.respond_to? :specification_version then
|
73
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
74
|
+
s.specification_version = 3
|
75
|
+
|
76
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
77
|
+
s.add_runtime_dependency(%q<ruck>, [">= 0"])
|
78
|
+
else
|
79
|
+
s.add_dependency(%q<ruck>, [">= 0"])
|
80
|
+
end
|
81
|
+
else
|
82
|
+
s.add_dependency(%q<ruck>, [">= 0"])
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
data/test/bench.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
|
2
|
+
puts "Testing how many Step ugens it takes to synthesize slower than real-time"
|
3
|
+
|
4
|
+
seconds = 4
|
5
|
+
|
6
|
+
# were we invoked as a ruck_ugen script, or stand-alone?
|
7
|
+
if __FILE__ == $0
|
8
|
+
# we were invoked like "ruby bench.rb"
|
9
|
+
# benchmark UGens without shreduling
|
10
|
+
|
11
|
+
puts "... without shreduling"
|
12
|
+
|
13
|
+
require "ruck"
|
14
|
+
require "ruck/ugen"
|
15
|
+
|
16
|
+
SAMPLE_RATE = 22050
|
17
|
+
TIME = SAMPLE_RATE * seconds
|
18
|
+
dac = Ruck::InChannel.new
|
19
|
+
count = 0
|
20
|
+
@now = 0
|
21
|
+
puts "Simulating #{TIME / SAMPLE_RATE} seconds at #{SAMPLE_RATE} sample rate"
|
22
|
+
loop do
|
23
|
+
Ruck::Generators::Step.new >> dac
|
24
|
+
count += 1
|
25
|
+
|
26
|
+
start = Time.now
|
27
|
+
TIME.to_i.times do
|
28
|
+
dac.next(@now)
|
29
|
+
@now += 1
|
30
|
+
end
|
31
|
+
|
32
|
+
time = Time.now - start
|
33
|
+
puts "#{count} ugens took #{time} sec to synthesize #{TIME / 1.seconds} sec"
|
34
|
+
|
35
|
+
break if time > (TIME / SAMPLE_RATE)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
# we were invoked by ruck_ugen
|
39
|
+
# benchmark UGens with shreduling
|
40
|
+
|
41
|
+
puts "... with shreduling"
|
42
|
+
|
43
|
+
TIME = seconds.seconds
|
44
|
+
count = 0
|
45
|
+
puts "Simulating #{TIME / 1.second} seconds at #{SAMPLE_RATE} sample rate"
|
46
|
+
loop do
|
47
|
+
Step.new >> blackhole
|
48
|
+
count += 1
|
49
|
+
|
50
|
+
start = Time.now
|
51
|
+
play TIME
|
52
|
+
time = Time.now - start
|
53
|
+
puts "#{count} ugens took #{time} sec to synthesize #{TIME / 1.seconds} sec"
|
54
|
+
|
55
|
+
break if time > (TIME / 1.second)
|
56
|
+
end
|
57
|
+
end
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruck-ugen
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Tom Lieber
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-07-10 00:00:00 -07:00
|
18
|
+
default_executable: ruck_ugen
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: ruck
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
description: " A ruck shreduler and mini audio unit generator framework inspired by ChucK.\n Includes library for reading and writing multi-channel WAV files, and some\n basic audio filters.\n"
|
33
|
+
email: tom@alltom.com
|
34
|
+
executables:
|
35
|
+
- ruck_ugen
|
36
|
+
extensions: []
|
37
|
+
|
38
|
+
extra_rdoc_files:
|
39
|
+
- README
|
40
|
+
files:
|
41
|
+
- .document
|
42
|
+
- .gitignore
|
43
|
+
- README
|
44
|
+
- Rakefile
|
45
|
+
- VERSION
|
46
|
+
- bin/ruck_ugen
|
47
|
+
- examples/ex01.rb
|
48
|
+
- examples/ex02.rb
|
49
|
+
- examples/ex03.rb
|
50
|
+
- examples/ex04.rb
|
51
|
+
- examples/ex05.rb
|
52
|
+
- examples/ex06.rb
|
53
|
+
- examples/ex07.rb
|
54
|
+
- examples/ex08.rb
|
55
|
+
- examples/ex09.rb
|
56
|
+
- examples/ex10.rb
|
57
|
+
- examples/ex11.rb
|
58
|
+
- lib/ruck/misc/linkage.rb
|
59
|
+
- lib/ruck/misc/riff.rb
|
60
|
+
- lib/ruck/ugen.rb
|
61
|
+
- lib/ruck/ugen/basic.rb
|
62
|
+
- lib/ruck/ugen/oscillators.rb
|
63
|
+
- lib/ruck/ugen/time_helpers.rb
|
64
|
+
- lib/ruck/ugen/ugen.rb
|
65
|
+
- lib/ruck/ugen/wav.rb
|
66
|
+
- ruck-ugen.gemspec
|
67
|
+
- test/bench.rb
|
68
|
+
has_rdoc: true
|
69
|
+
homepage: http://github.com/alltom/ruck-ugen
|
70
|
+
licenses: []
|
71
|
+
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options:
|
74
|
+
- --charset=UTF-8
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
segments:
|
89
|
+
- 0
|
90
|
+
version: "0"
|
91
|
+
requirements: []
|
92
|
+
|
93
|
+
rubyforge_project:
|
94
|
+
rubygems_version: 1.3.6
|
95
|
+
signing_key:
|
96
|
+
specification_version: 3
|
97
|
+
summary: ruck shreduler + mini audio unit generator framework inspired by ChucK
|
98
|
+
test_files:
|
99
|
+
- test/bench.rb
|
100
|
+
- examples/ex01.rb
|
101
|
+
- examples/ex02.rb
|
102
|
+
- examples/ex03.rb
|
103
|
+
- examples/ex04.rb
|
104
|
+
- examples/ex05.rb
|
105
|
+
- examples/ex06.rb
|
106
|
+
- examples/ex07.rb
|
107
|
+
- examples/ex08.rb
|
108
|
+
- examples/ex09.rb
|
109
|
+
- examples/ex10.rb
|
110
|
+
- examples/ex11.rb
|