ruck 0.1.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/.gitignore +2 -0
- data/README +85 -0
- data/Rakefile +25 -0
- data/VERSION +1 -0
- data/bin/ruck_glapp +77 -0
- data/bin/ruck_midi +143 -0
- data/bin/ruck_ugen +53 -0
- data/examples/glapp/ex01.rb +13 -0
- data/examples/midi/ex01.rb +24 -0
- data/examples/ugen/ex01.rb +24 -0
- data/examples/ugen/ex02.rb +2 -0
- data/examples/ugen/ex03.rb +8 -0
- data/examples/ugen/ex04.rb +14 -0
- data/examples/ugen/ex05.rb +9 -0
- data/examples/ugen/ex06.rb +10 -0
- data/examples/ugen/ex07.rb +35 -0
- data/examples/ugen/ex08.rb +28 -0
- data/examples/ugen/ex09.rb +26 -0
- data/examples/ugen/ex10.rb +15 -0
- data/examples/ugen/ex11.rb +10 -0
- data/examples/ugen/ex12.rb +9 -0
- data/lib/ruck.rb +13 -0
- data/lib/ruck/bench.rb +44 -0
- data/lib/ruck/misc/linkage.rb +22 -0
- data/lib/ruck/misc/metaid.rb +18 -0
- data/lib/ruck/misc/pcm_time_helpers.rb +29 -0
- data/lib/ruck/misc/riff.rb +71 -0
- data/lib/ruck/misc/wavparse.rb +35 -0
- data/lib/ruck/shreduling.rb +147 -0
- data/lib/ruck/ugen/general.rb +408 -0
- data/lib/ruck/ugen/oscillators.rb +106 -0
- data/lib/ruck/ugen/wav.rb +185 -0
- data/ruck.gemspec +94 -0
- metadata +102 -0
@@ -0,0 +1,185 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), "..", "misc", "riff")
|
3
|
+
|
4
|
+
module Ruck
|
5
|
+
module Generators
|
6
|
+
|
7
|
+
# saves all incoming samples in memory to export to disk later
|
8
|
+
# outputs 0.0 samples
|
9
|
+
class WavOut
|
10
|
+
include UGen
|
11
|
+
include Source
|
12
|
+
include MultiChannelTarget
|
13
|
+
|
14
|
+
attr_reader :filename
|
15
|
+
|
16
|
+
def initialize(attrs = {})
|
17
|
+
require_attrs attrs, [:filename]
|
18
|
+
@filename = attrs.delete(:filename)
|
19
|
+
@num_channels = attrs.delete(:num_channels) || 1
|
20
|
+
@bits_per_sample = attrs.delete(:bits_per_sample) || 16
|
21
|
+
parse_attrs attrs
|
22
|
+
|
23
|
+
@in_channels = (1..@num_channels).map { InChannel.new }
|
24
|
+
|
25
|
+
@sample_rate = SAMPLE_RATE
|
26
|
+
@samples = (1..@num_channels).map { [] }
|
27
|
+
@ins = []
|
28
|
+
@last = 0.0
|
29
|
+
|
30
|
+
# TODO: this is necessary, but if UGen graph were explicitly
|
31
|
+
# destructed, that would be nice.
|
32
|
+
at_exit { save }
|
33
|
+
end
|
34
|
+
|
35
|
+
def next(now)
|
36
|
+
return @last if @now == now
|
37
|
+
@now = now
|
38
|
+
@samples << @in_channels.map { |chan| chan.next now }
|
39
|
+
@last
|
40
|
+
end
|
41
|
+
|
42
|
+
def save
|
43
|
+
LOG.info "Saving WAV to #{@filename}..."
|
44
|
+
File.open(@filename, "wb") { |f| f.write encode }
|
45
|
+
end
|
46
|
+
|
47
|
+
def attr_names
|
48
|
+
[:filename]
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def encode
|
54
|
+
chunk("RIFF") do |riff|
|
55
|
+
riff << ascii("WAVE")
|
56
|
+
riff << chunk("fmt ") do |fmt|
|
57
|
+
fmt << short(1) # format = 1: PCM (no compression)
|
58
|
+
fmt << short(@num_channels)
|
59
|
+
fmt << int(@sample_rate)
|
60
|
+
fmt << int((@sample_rate * @num_channels * (@bits_per_sample / 8))) # byte-rate
|
61
|
+
fmt << short((@num_channels * @bits_per_sample/8)) # block align
|
62
|
+
fmt << short(@bits_per_sample) # bits/sample
|
63
|
+
end
|
64
|
+
riff << chunk("data") do |data|
|
65
|
+
range = 2 ** (@bits_per_sample - 1)
|
66
|
+
@samples.each do |sample_list|
|
67
|
+
sample_list.each { |sample| data << [sample * range].pack("s1") }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def int(i)
|
74
|
+
[i].pack("i1")
|
75
|
+
end
|
76
|
+
|
77
|
+
def short(s)
|
78
|
+
[s].pack("s1")
|
79
|
+
end
|
80
|
+
|
81
|
+
def ascii(str)
|
82
|
+
str.split("").pack("A1" * str.length)
|
83
|
+
end
|
84
|
+
|
85
|
+
def chunk(type, &block)
|
86
|
+
buf = ""
|
87
|
+
block.call(buf)
|
88
|
+
ascii(type) + int(buf.length) + buf
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
# plays sound stored in a RIFF WAV file
|
94
|
+
class WavIn
|
95
|
+
include UGen
|
96
|
+
include MultiChannelSource
|
97
|
+
|
98
|
+
linkable_attr :rate
|
99
|
+
linkable_attr :gain
|
100
|
+
attr_reader :filename
|
101
|
+
|
102
|
+
def initialize(attrs = {})
|
103
|
+
require_attrs attrs, [:filename]
|
104
|
+
@rate = 1.0
|
105
|
+
@gain = 1.0
|
106
|
+
@filename = attrs.delete(:filename)
|
107
|
+
parse_attrs attrs
|
108
|
+
|
109
|
+
@loaded = false
|
110
|
+
@playing = true
|
111
|
+
|
112
|
+
init_wav
|
113
|
+
end
|
114
|
+
|
115
|
+
def init_wav
|
116
|
+
riff = Riff::RiffReader.new(@filename).chunks.first
|
117
|
+
unless riff.type == "RIFF"
|
118
|
+
LOG.error "#{@filename}: Not RIFF!"
|
119
|
+
return
|
120
|
+
end
|
121
|
+
unless riff[0..3] == "WAVE"
|
122
|
+
LOG.error "#{@filename}: Not WAVE!"
|
123
|
+
return
|
124
|
+
end
|
125
|
+
|
126
|
+
riff.data_skip = 4 # skip "WAVE"
|
127
|
+
fmt = riff.chunks.first
|
128
|
+
@wav = riff.chunks.find { |c| c.type == "data" }
|
129
|
+
unless fmt[0..1].unpack("s1").first == 1
|
130
|
+
LOG.error "#{@filename}: Not PCM!"
|
131
|
+
return
|
132
|
+
end
|
133
|
+
|
134
|
+
@num_channels, @sample_rate, @byte_rate,
|
135
|
+
@block_align, @bits_per_sample =
|
136
|
+
fmt[2..15].unpack("s1i1i1s1s1")
|
137
|
+
@range = (2 ** (@bits_per_sample - 1)).to_f
|
138
|
+
|
139
|
+
@out_channels = (0..@num_channels-1).map { |chan| OutChannel.new self, chan }
|
140
|
+
@sample = [0.0] * @num_channels
|
141
|
+
@last = [0.0] * @num_channels
|
142
|
+
@now = [nil] * @num_channels
|
143
|
+
@rate_adjust = @sample_rate / SAMPLE_RATE
|
144
|
+
|
145
|
+
@loaded = true
|
146
|
+
end
|
147
|
+
|
148
|
+
def duration
|
149
|
+
@loaded ? @wav.size / @block_align / @rate_adjust : 0
|
150
|
+
end
|
151
|
+
|
152
|
+
def attr_names
|
153
|
+
[:filename, :rate]
|
154
|
+
end
|
155
|
+
|
156
|
+
def next(now, chan = 0)
|
157
|
+
return @last[chan] if @now[chan] == now
|
158
|
+
@now[chan] = now
|
159
|
+
|
160
|
+
return @last[chan] unless @loaded && @playing
|
161
|
+
|
162
|
+
offset = @sample[chan].to_i * @block_align
|
163
|
+
chan_offset = (chan * @bits_per_sample) / 8
|
164
|
+
|
165
|
+
if offset + @block_align > @wav.size
|
166
|
+
@playing = false
|
167
|
+
return @last[chan]
|
168
|
+
end
|
169
|
+
|
170
|
+
@last[chan] = @wav[offset + chan_offset, @bits_per_sample].unpack("s1").first / @range * gain
|
171
|
+
@sample[chan] += rate * @rate_adjust
|
172
|
+
@last[chan]
|
173
|
+
end
|
174
|
+
|
175
|
+
def play; @playing = true; end
|
176
|
+
def stop; @playing = false; end
|
177
|
+
|
178
|
+
def reset
|
179
|
+
@offset = 0
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
end
|
data/ruck.gemspec
ADDED
@@ -0,0 +1,94 @@
|
|
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}
|
8
|
+
s.version = "0.1.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{2009-11-16}
|
13
|
+
s.description = %q{ Ruck uses continuations and a simple scheduler to ensure "shreds"
|
14
|
+
(threads in Ruck) are woken at precisely the right time according
|
15
|
+
to its virtual clock. Schedulers can map virtual time to samples
|
16
|
+
in a WAV file, real time, time in a MIDI file, or anything else
|
17
|
+
by overriding "sim_to" in the Shreduler class.
|
18
|
+
|
19
|
+
A small library of useful unit generators and plenty of examples
|
20
|
+
are provided. See the README or the web page for details.
|
21
|
+
}
|
22
|
+
s.email = %q{tom@alltom.com}
|
23
|
+
s.executables = ["ruck_glapp", "ruck_midi", "ruck_ugen"]
|
24
|
+
s.extra_rdoc_files = [
|
25
|
+
"README"
|
26
|
+
]
|
27
|
+
s.files = [
|
28
|
+
".gitignore",
|
29
|
+
"README",
|
30
|
+
"Rakefile",
|
31
|
+
"VERSION",
|
32
|
+
"bin/ruck_glapp",
|
33
|
+
"bin/ruck_midi",
|
34
|
+
"bin/ruck_ugen",
|
35
|
+
"examples/glapp/ex01.rb",
|
36
|
+
"examples/midi/ex01.rb",
|
37
|
+
"examples/ugen/ex01.rb",
|
38
|
+
"examples/ugen/ex02.rb",
|
39
|
+
"examples/ugen/ex03.rb",
|
40
|
+
"examples/ugen/ex04.rb",
|
41
|
+
"examples/ugen/ex05.rb",
|
42
|
+
"examples/ugen/ex06.rb",
|
43
|
+
"examples/ugen/ex07.rb",
|
44
|
+
"examples/ugen/ex08.rb",
|
45
|
+
"examples/ugen/ex09.rb",
|
46
|
+
"examples/ugen/ex10.rb",
|
47
|
+
"examples/ugen/ex11.rb",
|
48
|
+
"examples/ugen/ex12.rb",
|
49
|
+
"lib/ruck.rb",
|
50
|
+
"lib/ruck/bench.rb",
|
51
|
+
"lib/ruck/misc/linkage.rb",
|
52
|
+
"lib/ruck/misc/metaid.rb",
|
53
|
+
"lib/ruck/misc/pcm_time_helpers.rb",
|
54
|
+
"lib/ruck/misc/riff.rb",
|
55
|
+
"lib/ruck/misc/wavparse.rb",
|
56
|
+
"lib/ruck/shreduling.rb",
|
57
|
+
"lib/ruck/ugen/general.rb",
|
58
|
+
"lib/ruck/ugen/oscillators.rb",
|
59
|
+
"lib/ruck/ugen/wav.rb",
|
60
|
+
"ruck.gemspec"
|
61
|
+
]
|
62
|
+
s.homepage = %q{http://github.com/alltom/ruck}
|
63
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
64
|
+
s.require_paths = ["lib"]
|
65
|
+
s.rubygems_version = %q{1.3.5}
|
66
|
+
s.summary = %q{strong timing for Ruby: cooperative threads on a virtual clock}
|
67
|
+
s.test_files = [
|
68
|
+
"examples/glapp/ex01.rb",
|
69
|
+
"examples/midi/ex01.rb",
|
70
|
+
"examples/ugen/ex01.rb",
|
71
|
+
"examples/ugen/ex02.rb",
|
72
|
+
"examples/ugen/ex03.rb",
|
73
|
+
"examples/ugen/ex04.rb",
|
74
|
+
"examples/ugen/ex05.rb",
|
75
|
+
"examples/ugen/ex06.rb",
|
76
|
+
"examples/ugen/ex07.rb",
|
77
|
+
"examples/ugen/ex08.rb",
|
78
|
+
"examples/ugen/ex09.rb",
|
79
|
+
"examples/ugen/ex10.rb",
|
80
|
+
"examples/ugen/ex11.rb",
|
81
|
+
"examples/ugen/ex12.rb"
|
82
|
+
]
|
83
|
+
|
84
|
+
if s.respond_to? :specification_version then
|
85
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
86
|
+
s.specification_version = 3
|
87
|
+
|
88
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
89
|
+
else
|
90
|
+
end
|
91
|
+
else
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruck
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tom Lieber
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-16 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: " Ruck uses continuations and a simple scheduler to ensure \"shreds\"\n (threads in Ruck) are woken at precisely the right time according\n to its virtual clock. Schedulers can map virtual time to samples\n in a WAV file, real time, time in a MIDI file, or anything else\n by overriding \"sim_to\" in the Shreduler class.\n \n A small library of useful unit generators and plenty of examples\n are provided. See the README or the web page for details.\n"
|
17
|
+
email: tom@alltom.com
|
18
|
+
executables:
|
19
|
+
- ruck_glapp
|
20
|
+
- ruck_midi
|
21
|
+
- ruck_ugen
|
22
|
+
extensions: []
|
23
|
+
|
24
|
+
extra_rdoc_files:
|
25
|
+
- README
|
26
|
+
files:
|
27
|
+
- .gitignore
|
28
|
+
- README
|
29
|
+
- Rakefile
|
30
|
+
- VERSION
|
31
|
+
- bin/ruck_glapp
|
32
|
+
- bin/ruck_midi
|
33
|
+
- bin/ruck_ugen
|
34
|
+
- examples/glapp/ex01.rb
|
35
|
+
- examples/midi/ex01.rb
|
36
|
+
- examples/ugen/ex01.rb
|
37
|
+
- examples/ugen/ex02.rb
|
38
|
+
- examples/ugen/ex03.rb
|
39
|
+
- examples/ugen/ex04.rb
|
40
|
+
- examples/ugen/ex05.rb
|
41
|
+
- examples/ugen/ex06.rb
|
42
|
+
- examples/ugen/ex07.rb
|
43
|
+
- examples/ugen/ex08.rb
|
44
|
+
- examples/ugen/ex09.rb
|
45
|
+
- examples/ugen/ex10.rb
|
46
|
+
- examples/ugen/ex11.rb
|
47
|
+
- examples/ugen/ex12.rb
|
48
|
+
- lib/ruck.rb
|
49
|
+
- lib/ruck/bench.rb
|
50
|
+
- lib/ruck/misc/linkage.rb
|
51
|
+
- lib/ruck/misc/metaid.rb
|
52
|
+
- lib/ruck/misc/pcm_time_helpers.rb
|
53
|
+
- lib/ruck/misc/riff.rb
|
54
|
+
- lib/ruck/misc/wavparse.rb
|
55
|
+
- lib/ruck/shreduling.rb
|
56
|
+
- lib/ruck/ugen/general.rb
|
57
|
+
- lib/ruck/ugen/oscillators.rb
|
58
|
+
- lib/ruck/ugen/wav.rb
|
59
|
+
- ruck.gemspec
|
60
|
+
has_rdoc: true
|
61
|
+
homepage: http://github.com/alltom/ruck
|
62
|
+
licenses: []
|
63
|
+
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options:
|
66
|
+
- --charset=UTF-8
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
version:
|
81
|
+
requirements: []
|
82
|
+
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 1.3.5
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: "strong timing for Ruby: cooperative threads on a virtual clock"
|
88
|
+
test_files:
|
89
|
+
- examples/glapp/ex01.rb
|
90
|
+
- examples/midi/ex01.rb
|
91
|
+
- examples/ugen/ex01.rb
|
92
|
+
- examples/ugen/ex02.rb
|
93
|
+
- examples/ugen/ex03.rb
|
94
|
+
- examples/ugen/ex04.rb
|
95
|
+
- examples/ugen/ex05.rb
|
96
|
+
- examples/ugen/ex06.rb
|
97
|
+
- examples/ugen/ex07.rb
|
98
|
+
- examples/ugen/ex08.rb
|
99
|
+
- examples/ugen/ex09.rb
|
100
|
+
- examples/ugen/ex10.rb
|
101
|
+
- examples/ugen/ex11.rb
|
102
|
+
- examples/ugen/ex12.rb
|