PortAudio.jl/src/nodes.jl

87 lines
2 KiB
Julia
Raw Normal View History

export SinOsc, AudioMixer, ArrayPlayer, AudioInput
#### SinOsc ####
# Generates a sin tone at the given frequency
type SinOsc <: AudioNode
freq::Real
phase::FloatingPoint
function SinOsc(freq::Real)
new(freq, 0.0)
end
end
function render(node::SinOsc, device_input::AudioBuf, info::DeviceInfo)
phase = AudioSample[1:info.buf_size] * 2pi * node.freq / info.sample_rate
phase += node.phase
node.phase = phase[end]
return sin(phase)
end
#### AudioMixer ####
# Mixes a set of inputs equally
type AudioMixer <: AudioNode
mix_inputs::Array{AudioNode}
function AudioMixer{T <: AudioNode}(mix_inputs::Array{T})
new(mix_inputs)
end
function AudioMixer()
new(AudioNode[])
end
end
function render(node::AudioMixer, device_input::AudioBuf, info::DeviceInfo)
# TODO: we may want to pre-allocate this buffer and share between render
# calls
mix_buffer = zeros(AudioSample, info.buf_size)
for in_node in node.mix_inputs
mix_buffer += render(in_node, device_input, info)
end
return mix_buffer
end
#### Array Player ####
# Plays a AudioBuf by rendering it out piece-by-piece
type ArrayPlayer <: AudioNode
arr::AudioBuf
arr_index::Int
function ArrayPlayer(arr::AudioBuf)
new(arr, 1)
end
end
function render(node::ArrayPlayer, device_input::AudioBuf, info::DeviceInfo)
# TODO: this should remove itself from the render tree when playback is
# complete
i = node.arr_index
range_end = min(i + info.buf_size-1, length(node.arr))
output = node.arr[i:range_end]
if length(output) < info.buf_size
output = vcat(output, zeros(AudioSample, info.buf_size - length(output)))
end
node.arr_index = range_end + 1
return output
end
#### AudioInput ####
# Renders incoming audio input from the hardware
type AudioInput <: AudioNode
channel::Int
end
function render(node::AudioInput, device_input::AudioBuf, info::DeviceInfo)
@assert size(device_input, 1) == info.buf_size
return device_input[:, node.channel]
end