ruck 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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