diff --git a/src/AudioIO.jl b/src/AudioIO.jl index c2a87ef..73427ab 100644 --- a/src/AudioIO.jl +++ b/src/AudioIO.jl @@ -1,7 +1,7 @@ module AudioIO # export the basic API -export play +export play, stop # default stream used when none is given _stream = nothing @@ -76,4 +76,8 @@ function play{T <: Unsigned}(arr::Array{T}, args...) play(arr, args...) end +function stop(node::AudioNode) + node.active = false +end + end # module AudioIO diff --git a/src/nodes.jl b/src/nodes.jl index d6bedbd..9b4bd33 100644 --- a/src/nodes.jl +++ b/src/nodes.jl @@ -5,11 +5,12 @@ export SinOsc, AudioMixer, ArrayPlayer, AudioInput # Generates a sin tone at the given frequency type SinOsc <: AudioNode + active::Bool freq::Real phase::FloatingPoint function SinOsc(freq::Real) - new(freq, 0.0) + new(true, freq, 0.0) end end @@ -17,7 +18,7 @@ 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), true + return sin(phase), node.active end #### AudioMixer #### @@ -25,14 +26,15 @@ end # Mixes a set of inputs equally type AudioMixer <: AudioNode + active::Bool mix_inputs::Array{AudioNode} function AudioMixer{T <: AudioNode}(mix_inputs::Array{T}) - new(mix_inputs) + new(true, mix_inputs) end function AudioMixer() - new(AudioNode[]) + new(true, AudioNode[]) end end @@ -44,7 +46,7 @@ function render(node::AudioMixer, device_input::AudioBuf, info::DeviceInfo) in_buffer, active = render(in_node, device_input, info) mix_buffer += in_buffer end - return mix_buffer, true + return mix_buffer, node.active end #### Array Player #### @@ -52,11 +54,12 @@ end # Plays a AudioBuf by rendering it out piece-by-piece type ArrayPlayer <: AudioNode + active::Bool arr::AudioBuf arr_index::Int function ArrayPlayer(arr::AudioBuf) - new(arr, 1) + new(true, arr, 1) end end @@ -67,10 +70,13 @@ function render(node::ArrayPlayer, device_input::AudioBuf, info::DeviceInfo) range_end = min(i + info.buf_size-1, length(node.arr)) output = node.arr[i:range_end] if length(output) < info.buf_size + # we're finished with the array, pad with zeros and clear our active + # flag output = vcat(output, zeros(AudioSample, info.buf_size - length(output))) + node.active = false end node.arr_index = range_end + 1 - return output, true + return output, node.active end #### AudioInput #### diff --git a/test/test_nodes.jl b/test/test_nodes.jl index d7f705f..fdb281e 100644 --- a/test/test_nodes.jl +++ b/test/test_nodes.jl @@ -38,6 +38,10 @@ render_output, active = AudioIO.render(mix, dev_input, test_info) @test render_output == 2 * AudioIO.AudioSample[1:test_info.buf_size] @test active +stop(mix) +render_output, active = AudioIO.render(mix, dev_input, test_info) +@test !active + info("Testing SinOSC...") freq = 440 t = linspace(1 / test_info.sample_rate, @@ -48,3 +52,27 @@ osc = SinOsc(freq) render_output, active = AudioIO.render(osc, dev_input, test_info) @test_approx_eq(render_output, test_vect) @test active +stop(osc) +render_output, active = AudioIO.render(osc, dev_input, test_info) +@test !active + +info("Testing ArrayPlayer...") +v = rand(AudioIO.AudioSample, 44100) +player = ArrayPlayer(v) +render_output, active = AudioIO.render(player, dev_input, test_info) +@test render_output == v[1:test_info.buf_size] +@test active +render_output, active = AudioIO.render(player, dev_input, test_info) +@test render_output == v[(test_info.buf_size + 1) : (2*test_info.buf_size)] +@test active +stop(player) +render_output, active = AudioIO.render(player, dev_input, test_info) +@test !active + +# give a vector just a bit larger than 1 buffer size +v = rand(AudioIO.AudioSample, test_info.buf_size + 1) +player = ArrayPlayer(v) +_, active = AudioIO.render(player, dev_input, test_info) +@test active +_, active = AudioIO.render(player, dev_input, test_info) +@test !active