Permalink
Browse files

basic buffer functionality

  • Loading branch information...
Macario
Macario committed Jul 19, 2009
1 parent 92fc776 commit f383bc025db22441e447f1446737f36d8afec644
Showing with 161 additions and 61 deletions.
  1. +40 −39 lib/scruby/audio/buffer.rb
  2. +25 −1 lib/scruby/audio/server.rb
  3. +47 −21 spec/audio/buffer_spec.rb
  4. +49 −0 spec/audio/server_spec.rb
@@ -1,69 +1,49 @@
module Scruby
class Buffer
# allocReadChannel
# allocReadMsg
# alloc ReadCannelMsg
# read
# readChannel
# readNoUpdate
# readMsg
# readChannelMsg
# cueSoundFile
# cueSoundFilMsg
# loadCollection
# sendCollection
# streamCollection
# loadToFloatArray
# getToFloatArray
# write
# writeMsg
# free
# zero
# zeroMsg
# set
# setMsg
# setn
# setnMsgArgs
# setnMsg
# get
# getMsg
# getn
# getnMsg
# fill
# fillMsg
# normalize
# gen
# genMsg
# sine1
# ...
# copy
# copyData
# copyMsg
# close
# closeMsg
# query
# updateInfo
# cache
# uncache
# queryDone
# printOn
# play
# duration
# asBufWithValues
attr_reader :server
attr_accessor :path, :frames, :channels, :rate
def initialize server, frames = -1, channels = 1
@server, @frames, @channels = server, frames, channels
@server.allocate_buffers self
end
def allocate &message
message ||= 0
@server.allocate_buffers self
@server.send '/b_alloc', buffnum, frames, channels, message.value(self)
self
end
@@ -73,19 +53,31 @@ def buffnum
end
alias :as_ugen_input :buffnum
# alias :as_control_input :buffnum
def free &message
message ||= 0
@server.send "/b_free", buffnum, message.value(self)
@server.buffers.delete self
end
# :nodoc:
def allocate_and_read path, start, frames, &message
@server.allocate_buffers self
message ||= ["/b_query", buffnum]
@server.send "/b_allocRead", buffnum, @path = path, start, frames, message.value(self)
self
end
def allocate_read_channel path, start, frames, channels, &message
@server.allocate_buffers self
message ||= ["/b_query", buffnum]
@server.send *(["/b_allocReadChannel", buffnum, path, start, frames] + channels << message.value(self))
self
end
class << self
# Allocate a buffer and immediately read a soundfile into it.
def read server, path, start = 0, frames = -1, &message
buffer = new server, &message
buffer.allocate_and_read path, start, frames
def allocate server, frames = -1, channels = 1, &message
new(server, frames, channels).allocate &message
end
def cue_sound_file server, path, start, channels = 2, buff_size = 32768, &message
@@ -95,23 +87,32 @@ def cue_sound_file server, path, start, channels = 2, buff_size = 32768, &messag
end
end
def allocate server, frames = -1, channels = 1, &message
buffer = new server, frames, channels
buffer.allocate &message
# Allocate a buffer and immediately read a soundfile into it.
def read server, path, start = 0, frames = -1, &message
buffer = new server, &message
buffer.allocate_and_read path, start, frames
end
def read_channel server, path, start = 0, frames = -1, channels = [], &message
new(server, frames, channels).allocate_read_channel path, start, frames, channels, &message
end
named_arguments_for :allocate, :read, :cue_sound_file
# allocConsecutive
# readChannel
def alloc_consecutive buffers, server, frames = -1, channels = 1, &message
buffers = Array.new(buffers){ new server, frames, channels }
server.allocate_buffers buffers
message ||= 0
buffers.each do |buff|
server.send '/b_alloc', buff.buffnum, frames, channels, message.value(buff)
end
end
# def send_collection server, collection, channels = 1, wait = 0.0, &message
# end
named_arguments_for :allocate, :read, :cue_sound_file, :alloc_consecutive, :read_channel
# readNoUpdate
# loadCollection
# sendCollection
# freeAllinitServerCache
# initServerCache
# clearServerCaches
# cachedBuffersDo
# cachedBufferAt
# loadDialog
end
end
@@ -118,12 +118,36 @@ def send_synth_def synth_def
send Bundle.new( nil, Message.new( '/d_recv', Blob.new(synth_def.encode), 0 ) )
end
# This method should not be directly called, it will add passed +buffers+ to the @buffers array, the +Buffer#buffnum+
# will be it's index in this array. Max number of buffers is 1024.
# It will try to fill first consecutive nil indices of the array and if there are not enough consecutive nil indices for the +buffers+
# passed and the maximum number is not reached it will push the buffers to the array, otherwise will raise an error.
def allocate_buffers *buffers
buffers.peel!
if @buffers.compact.size + buffers.size > 1024
raise SCError, 'No more buffer numbers -- free some buffers before allocating more.'
end
@buffers += buffers
return @buffers += buffers unless @buffers.index nil # just concat arrays if no nil item in @buffers
indices = []
@buffers.each_with_index do |item, index| # find n number of consecutive nil indices
break if indices.size >= buffers.size
if item.nil?
indices << index
else
indices.clear
end
end
case
when indices.size >= buffers.size
@buffers[indices.first, buffers.size] = buffers
when @buffers.size + buffers.size <= 1024
@buffers += buffers
else
raise SCError, "No block of #{ buffers.size } consecutive buffer slots is available."
end
end
@@servers = []
@@ -19,26 +19,6 @@ def puts string
end
describe Buffer do
describe '#server buffer allocation' do
before do
@server = Server.new
end
it "should register itself in server" do
buffer = Buffer.new @server
@server.buffers.should include(buffer)
end
it "should allow less than 1024 buffers" do
@server.allocate_buffers( (1..1024).map{ mock(Buffer) } )
@server.buffers.size.should == 1024
end
it "should not allow more than 1024 buffers" do
lambda { @server.allocate_buffers( (1..1025).map{ mock(Buffer) } ) }.should raise_error(SCError)
end
end
describe "messaging" do
before :all do
@server = Server.new
@@ -99,6 +79,52 @@ def puts string
it "should allow passing a completion message"
end
describe '#free' do
before do
@buffer = Buffer.allocate @server, 44100 * 10.0, 2
@buffer2 = Buffer.allocate @server, 44100 * 10.0, 2
@bnum = @buffer2.buffnum
@buffer2.free
sleep 0.1
end
it "should remove itself from the server @buffers array and send free message" do
@buffer2.buffnum.should be_nil
@server.output.should =~ %r{\[ "/b_free", #{ @bnum }, 0 \]}
end
it "should allow passing a completion message"
end
describe 'Buffer.alloc_consecutive' do
before do
@buffers = Buffer.alloc_consecutive 8, @server, 4096, 2
sleep 0.1
end
it "should send alloc message for each Buffer and instantiate" do
@buffers.should have(8).buffers
@buffers.each do |buff|
@server.output.should =~ %r{\[ "/b_alloc", #{ buff.buffnum }, 4096, 2, 0 \]}
end
end
it "should allow passing a message"
end
describe 'Buffer.read_channel' do
before do
@buffer = Buffer.read_channel @server, "sounds/SinedPink.aiff", :channels => [0]
sleep 0.1
end
it "should allocate and send /b_allocReadChannel message" do
@buffer.should be_a(Buffer)
@server.output.should =~ %r{\[ "/b_allocReadChannel", #{ @buffer.buffnum }, "sounds/SinedPink.aiff", 0, -1, 0, DATA\[20\] \]}
@server.output.should =~ /73 6f 75 6e 64 73 2f 53 69 6e 65 64 50 69 6e 6b/
end
end
end
end
@@ -25,6 +25,12 @@ def puts string
end
end
class Scruby::Audio::Buffer
def == other
self.class == other.class
end
end
describe Message do
it "should encode array as Message Blob" do
m = Message.new "/b_allocRead", 1, "path", 1, -1, ["/b_query", 1]
@@ -91,6 +97,49 @@ def puts string
@server.output.should =~ %r{\[ "#bundle", 1, \n\s*\[ "/d_recv", DATA\[56\], 0 \]\n\]}
end
end
describe 'buffers' do
before do
@server = Server.new
end
it "should allow less than 1024 buffers" do
@server.allocate_buffers( (1..1024).map{ mock(Buffer) } )
@server.buffers.size.should == 1024
end
it "should not allow more than 1024 buffers" do
lambda { @server.allocate_buffers( (1..1025).map{ Buffer.new } ) }.should raise_error(SCError)
end
it "should try to allocate lowest nil slot" do
@server.buffers.concat([nil, nil, Buffer.new, nil, nil, nil, Buffer.new])
@server.allocate_buffers buffer = Buffer.new
@server.buffers.index(buffer).should == 0
end
it "should allocate various buffers in available indices" do
@server.buffers.concat([nil, nil, Buffer.new, nil, nil, nil, Buffer.new])
@server.allocate_buffers Buffer.new, Buffer.new, Buffer.new
@server.buffers.should == [nil, nil, Buffer.new, Buffer.new, Buffer.new, Buffer.new, Buffer.new]
end
it "should allocate by appending various buffers" do
@server.buffers.concat([nil, nil, Buffer.new, nil, nil, nil, Buffer.new])
@server.allocate_buffers Buffer.new, Buffer.new, Buffer.new, Buffer.new
@server.buffers.should == [nil, nil, Buffer.new, nil, nil, nil, Buffer.new, Buffer.new, Buffer.new, Buffer.new, Buffer.new]
end
it "should not surpass the max buffer limit" do
@server.allocate_buffers( (1..1022).map{ |i| Buffer.new if i % 2 == 0 } )
lambda { @server.allocate_buffers Buffer.new, Buffer.new, Buffer.new }.should raise_error
end
it "should allocate by appending" do
@server.allocate_buffers( (1..1021).map{ |i| Buffer.new if i % 2 == 0 } )
@server.allocate_buffers Buffer.new, Buffer.new, Buffer.new
@server.buffers.size.should == 1024
end
end
end

0 comments on commit f383bc0

Please sign in to comment.