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