Added support for consecutive linear ramps.
This commit is contained in:
parent
16857615d3
commit
4eb15ae29f
2 changed files with 75 additions and 22 deletions
32
examples/ramp.jl
Normal file
32
examples/ramp.jl
Normal file
|
@ -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)
|
63
src/nodes.jl
63
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
|
||||
return node.buf
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue