From 4eb15ae29fe1999d486ed6abb1a0cf619a7e46a0 Mon Sep 17 00:00:00 2001 From: Calder Coalson Date: Sat, 28 Jun 2014 15:22:35 -0500 Subject: [PATCH] Added support for consecutive linear ramps. --- examples/ramp.jl | 32 ++++++++++++++++++++++++ src/nodes.jl | 65 ++++++++++++++++++++++++++++++++---------------- 2 files changed, 75 insertions(+), 22 deletions(-) create mode 100644 examples/ramp.jl diff --git a/examples/ramp.jl b/examples/ramp.jl new file mode 100644 index 0000000..9562541 --- /dev/null +++ b/examples/ramp.jl @@ -0,0 +1,32 @@ +using AudioIO + +# Give PortAudio time to load +play([0]) +sleep(2) + +println(""" + * + * * + * * * + * * * * + * * * * * +* * * * * * +""") +wave = SinOsc(440) * LinRamp(0.0,1.0,2.0) +play(wave) +sleep(2) +stop(wave) + + +print(""" + * + * * * + * * * * * + * * * * * * * + * * * * * * * * * +* * * * * * * * * * * +""") +wave = SinOsc(440) * LinRamp([0.0,1.0,0.0], [2.0,2.0]) +play(wave) +sleep(4) +stop(wave) \ No newline at end of file diff --git a/src/nodes.jl b/src/nodes.jl index 9c4fb9d..711e53e 100644 --- a/src/nodes.jl +++ b/src/nodes.jl @@ -276,40 +276,61 @@ end typealias AudioInput AudioNode{InputRenderer} export AudioInput -#### Ramp #### +#### LinRamp #### type LinRampRenderer <: AudioRenderer - start::AudioSample - finish::AudioSample - dur::Float32 + key_samples::Array{AudioSample} + key_durations::Array{Float32} + buf::AudioBuf - LinRampRenderer(start, finish, dur) = new(start, finish, dur, AudioSample[]) + LinRampRenderer(start, finish, dur) = LinRampRenderer([start,finish], [dur]) + + LinRampRenderer(key_samples, key_durations) = + LinRampRenderer( + [convert(AudioSample,s) for s in key_samples], + [convert(Float32,d) for d in key_durations] + ) + + function LinRampRenderer(key_samples::Array{AudioSample}, key_durations::Array{Float32}) + @assert length(key_samples) == length(key_durations) + 1 + new(key_samples, key_durations, AudioSample[]) + end end typealias LinRamp AudioNode{LinRampRenderer} export LinRamp - function render(node::LinRampRenderer, device_input::AudioBuf, info::DeviceInfo) - ramp_samples = int(node.dur * info.sample_rate) - block_samples = min(ramp_samples, info.buf_size) - if length(node.buf) != block_samples - resize!(node.buf, block_samples) + # Grow buffer if it's too small + if length(node.buf) < info.buf_size + resize!(node.buf, info.buf_size) end - out_block = node.buf + # Fill the buffer as long as there are more segments + dt::Float32 = 1/info.sample_rate i::Int = 1 - val::AudioSample = node.start - inc::AudioSample = (node.finish - node.start) / ramp_samples - while i <= block_samples - out_block[i] = val - i += 1 - val += inc + while i <= info.buf_size && length(node.key_samples) > 1 + + # Fill as much of the buffer as we can with the current segment + ds::Float32 = (node.key_samples[2] - node.key_samples[1]) / node.key_durations[1] / info.sample_rate + while i <= info.buf_size + node.buf[i] = node.key_samples[1] + node.key_samples[1] += ds + node.key_durations[1] -= dt + i += 1 + + # Discard segment if we're finished + if node.key_durations[1] <= 0 + if length(node.key_durations) > 1 + node.key_durations[2] -= node.key_durations[1] + end + shift!(node.key_samples) + shift!(node.key_durations) + break + end + end end - node.dur -= block_samples / info.sample_rate - node.start = val - - return out_block -end + return node.buf +end \ No newline at end of file