drops allocation of MixRenderer to 64bytes

This commit is contained in:
Spencer Russell 2014-06-25 23:16:07 -04:00
parent b8802449c9
commit 8cc51a435c
2 changed files with 20 additions and 9 deletions

View file

@ -80,6 +80,9 @@ end
type MixRenderer <: AudioRenderer type MixRenderer <: AudioRenderer
inputs::Vector{AudioNode} inputs::Vector{AudioNode}
buf::AudioBuf
MixRenderer(inputs) = new(inputs, AudioSample[])
end end
typealias AudioMixer AudioNode{MixRenderer} typealias AudioMixer AudioNode{MixRenderer}
@ -88,21 +91,23 @@ AudioMixer() = AudioMixer(AudioNode[])
export AudioMixer export AudioMixer
function render(node::MixRenderer, device_input::AudioBuf, info::DeviceInfo) function render(node::MixRenderer, device_input::AudioBuf, info::DeviceInfo)
# TODO: we probably want to pre-allocate this buffer and share between if length(node.buf) != info.buf_size
# render calls. Unfortunately we don't know the right size when the object resize!(node.buf, info.buf_size)
# is created, so maybe we check the size on every render call and only end
# re-allocate when the size changes? I suppose that's got to be cheaper mix_buffer = node.buf
# than the GC and allocation every frame
mix_buffer = zeros(AudioSample, info.buf_size)
n_inputs = length(node.inputs) n_inputs = length(node.inputs)
i = 1 i = 1
max_samples = 0 max_samples = 0
fill!(mix_buffer, 0)
while i <= n_inputs while i <= n_inputs
rendered = render(node.inputs[i], device_input, info)::AudioBuf rendered = render(node.inputs[i], device_input, info)::AudioBuf
nsamples = length(rendered) nsamples = length(rendered)
max_samples = max(max_samples, nsamples) max_samples = max(max_samples, nsamples)
mix_buffer[1:nsamples] .+= rendered j::Int = 1
while j <= nsamples
mix_buffer[j] += rendered[j]
j += 1
end
if nsamples < info.buf_size if nsamples < info.buf_size
deleteat!(node.inputs, i) deleteat!(node.inputs, i)
n_inputs -= 1 n_inputs -= 1
@ -110,7 +115,12 @@ function render(node::MixRenderer, device_input::AudioBuf, info::DeviceInfo)
i += 1 i += 1
end end
end end
if max_samples < length(mix_buffer)
return mix_buffer[1:max_samples] return mix_buffer[1:max_samples]
else
# save the allocate and copy if we don't need to
return mix_buffer
end
end end
Base.push!(mixer::AudioMixer, node::AudioNode) = push!(mixer.renderer.inputs, node) Base.push!(mixer::AudioMixer, node::AudioNode) = push!(mixer.renderer.inputs, node)

View file

@ -46,6 +46,7 @@ testnode = TestNode(test_info.buf_size)
mix = AudioMixer([testnode]) mix = AudioMixer([testnode])
render_output = render(mix, dev_input, test_info) render_output = render(mix, dev_input, test_info)
@test render_output == AudioSample[1:test_info.buf_size] @test render_output == AudioSample[1:test_info.buf_size]
@test 100 > (@allocated render(mix, dev_input, test_info))
test1 = TestNode(test_info.buf_size) test1 = TestNode(test_info.buf_size)
test2 = TestNode(test_info.buf_size) test2 = TestNode(test_info.buf_size)