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.
@@ -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