Skip to content

Commit f4c300d

Browse files
authored
Merge pull request #21 from JuliaAudio/06_depwarn
updates for 0.6, some extra read/write capabilities
2 parents 3828970 + af604a8 commit f4c300d

20 files changed

Lines changed: 378 additions & 296 deletions

.travis.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ os:
44
- linux
55
- osx
66
julia:
7-
# - release
8-
- 0.4
9-
- 0.5
7+
- 0.6
108
notifications:
119
email: false
1210
script:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ write(wrapper, source)
136136

137137
The `ResampleSink` wrapper type wraps around a sink. Writing to this wrapper sink will resample the given data and pass it to the original sink. It maintains state between writes so that the interpolation is correct across the boundaries of multiple writes.
138138

139-
Currently `ResampleSink` handles resampling with simple linear interpolation and no lowpass filtering when downsampling. In the future we will likely implement other resampling methods.
139+
`ResampleSink` handles resampling with polyphase FIR resampling filter.
140140

141141
### Channel Conversion
142142

REQUIRE

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
julia 0.4
1+
julia 0.6-
22
SIUnits
33
FixedPointNumbers
4-
Compat 0.8.8
54
DSP

appveyor.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
environment:
22
matrix:
3-
- JULIAVERSION: "julialang/bin/winnt/x86/0.4/julia-0.4-latest-win32.exe"
4-
- JULIAVERSION: "julialang/bin/winnt/x64/0.4/julia-0.4-latest-win64.exe"
5-
- JULIAVERSION: "julialang/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe"
6-
- JULIAVERSION: "julialang/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe"
3+
- JULIAVERSION: "julialang/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
74

85
notifications:
96
- provider: Email

runtests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Runs the SampledSignals tests including generating an lcov.info file
44

55
# abort on failure
6-
set -e
6+
# set -e
77

88
julia -e 'using Coverage; clean_folder(".");'
99
julia --color=yes --inline=no --code-coverage=user test/runtests.jl

src/Interval.jl

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ is defined for Intervals of `Number` and `Dates.AbstractTime`.
1010
### Type parameters
1111
1212
```julia
13-
immutable Interval{T}
13+
struct Interval{T}
1414
```
1515
* `T` : the type of the interval's endpoints. Must be a concrete leaf type.
1616
@@ -35,16 +35,16 @@ A[0.0 .. 0.5]
3535
```
3636
3737
""" ->
38-
immutable Interval{T}
38+
struct Interval{T}
3939
lo::T
4040
hi::T
41-
function Interval(lo, hi)
41+
function Interval{T}(lo, hi) where {T}
4242
lo <= hi ? new(lo, hi) : throw(ArgumentError("lo must be less than or equal to hi"))
4343
end
4444
end
45-
Interval{T}(a::T,b::T) = Interval{T}(a,b)
45+
Interval(a::T,b::T) where {T} = Interval{T}(a,b)
4646
# Allow promotion during construction, but only if it results in a leaf type
47-
function Interval{T,S}(a::T, b::S)
47+
function Interval(a::T, b::S) where {T, S}
4848
(a2, b2) = promote(a, b)
4949
typeof(a2) == typeof(b2) || throw(ArgumentError("cannot promote $a and $b to a common type"))
5050
Interval(a2, b2)
@@ -53,9 +53,9 @@ const .. = Interval
5353

5454
Base.print(io::IO, i::Interval) = print(io, "$(i.lo)..$(i.hi)")
5555

56-
Base.convert{T}(::Type{Interval{T}}, x::T) = Interval{T}(x,x)
57-
Base.convert{T,S}(::Type{Interval{T}}, x::S) = (y=convert(T, x); Interval{T}(y,y))
58-
Base.convert{T}(::Type{Interval{T}}, w::Interval) = Interval{T}(convert(T, w.lo), convert(T, w.hi))
56+
Base.convert(::Type{Interval{T}}, x::T) where {T} = Interval{T}(x,x)
57+
Base.convert(::Type{Interval{T}}, x::S) where {T, S} = (y=convert(T, x); Interval{T}(y,y))
58+
Base.convert(::Type{Interval{T}}, w::Interval) where {T} = Interval{T}(convert(T, w.lo), convert(T, w.hi))
5959

6060
# Promotion rules for "promiscuous" types like Intervals and SIUnits, which both
6161
# simply wrap any Number, are often ambiguous. That is, which type should "win"
@@ -76,10 +76,10 @@ Base.convert{T}(::Type{Interval{T}}, w::Interval) = Interval{T}(convert(T, w.lo)
7676
# downside is that Intervals are not as useful as they could be; they really
7777
# could be considered as <: Number themselves. We do this in general for any
7878
# supported Scalar:
79-
typealias Scalar Union{Number, Dates.AbstractTime}
80-
Base.promote_rule{T<:Scalar}(::Type{Interval{T}}, ::Type{T}) = Interval{T}
81-
Base.promote_rule{T,S<:Scalar}(::Type{Interval{T}}, ::Type{S}) = Interval{promote_type(T,S)}
82-
Base.promote_rule{T,S}(::Type{Interval{T}}, ::Type{Interval{S}}) = Interval{promote_type(T,S)}
79+
const Scalar = Union{Number, Dates.AbstractTime}
80+
Base.promote_rule(::Type{Interval{T}}, ::Type{T}) where {T<:Scalar} = Interval{T}
81+
Base.promote_rule(::Type{Interval{T}}, ::Type{S}) where {T,S<:Scalar} = Interval{promote_type(T,S)}
82+
Base.promote_rule(::Type{Interval{T}}, ::Type{Interval{S}}) where {T,S} = Interval{promote_type(T,S)}
8383

8484
import Base: ==, +, -, *, /, ^
8585
==(a::Interval, b::Interval) = a.lo == b.lo && a.hi == b.hi

src/SampleBuf.jl

Lines changed: 80 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
abstract AbstractSampleBuf{T, N} <: AbstractArray{T, N}
1+
abstract type AbstractSampleBuf{T, N} <: AbstractArray{T, N} end
22

33
"""
44
Represents a multi-channel regularly-sampled buffer that stores its own sample
@@ -8,13 +8,13 @@ buffer will be an MxC matrix. So a 1-second stereo audio buffer sampled at
88
44100Hz with 32-bit floating-point samples in the time domain would have the
99
type SampleBuf{Float32, 2}.
1010
"""
11-
type SampleBuf{T, N} <: AbstractSampleBuf{T, N}
11+
mutable struct SampleBuf{T, N} <: AbstractSampleBuf{T, N}
1212
data::Array{T, N}
1313
samplerate::Float64
1414
end
1515

1616
# define constructor so conversion is applied to `sr`
17-
SampleBuf{T, N}(arr::Array{T, N}, sr::Real) = SampleBuf{T, N}(arr, sr)
17+
SampleBuf(arr::Array{T, N}, sr::Real) where {T, N} = SampleBuf{T, N}(arr, sr)
1818

1919
"""
2020
Represents a multi-channel regularly-sampled buffer representing the frequency-
@@ -24,16 +24,16 @@ C-channel buffer will be an MxC matrix. So a 1-second stereo audio buffer
2424
sampled at 44100Hz with 32-bit floating-point samples in the time domain would
2525
have the type SampleBuf{Float32, 2}.
2626
"""
27-
type SpectrumBuf{T, N} <: AbstractSampleBuf{T, N}
27+
mutable struct SpectrumBuf{T, N} <: AbstractSampleBuf{T, N}
2828
data::Array{T, N}
2929
samplerate::Float64
3030
end
3131

3232
# define constructor so conversion is applied to `sr`
33-
SpectrumBuf{T, N}(arr::Array{T, N}, sr::Real) = SpectrumBuf{T, N}(arr, sr)
33+
SpectrumBuf(arr::Array{T, N}, sr::Real) where {T, N} = SpectrumBuf{T, N}(arr, sr)
3434

35-
SampleBuf(T::Type, sr, dims...) = SampleBuf(Array(T, dims...), sr)
36-
SpectrumBuf(T::Type, sr, dims...) = SpectrumBuf(Array(T, dims...), sr)
35+
SampleBuf(T::Type, sr, dims...) = SampleBuf(Array{T}(dims...), sr)
36+
SpectrumBuf(T::Type, sr, dims...) = SpectrumBuf(Array{T}(dims...), sr)
3737
SampleBuf(T::Type, sr, len::SecondsQuantity) = SampleBuf(T, sr, round(Int, float(len)*sr))
3838
SampleBuf(T::Type, sr, len::SecondsQuantity, ch) = SampleBuf(T, sr, round(Int, float(len)*sr), ch)
3939
SpectrumBuf(T::Type, sr, len::HertzQuantity) = SpectrumBuf(T, sr, round(Int, float(len)*sr))
@@ -46,8 +46,8 @@ SpectrumBuf(T::Type, sr, len::HertzQuantity, ch) = SpectrumBuf(T, sr, round(Int,
4646

4747
# audio methods
4848
samplerate(buf::AbstractSampleBuf) = buf.samplerate
49-
nchannels{T}(buf::AbstractSampleBuf{T, 2}) = size(buf.data, 2)
50-
nchannels{T}(buf::AbstractSampleBuf{T, 1}) = 1
49+
nchannels(buf::AbstractSampleBuf{T, 2}) where {T} = size(buf.data, 2)
50+
nchannels(buf::AbstractSampleBuf{T, 1}) where {T} = 1
5151
nframes(buf::AbstractSampleBuf) = size(buf.data, 1)
5252

5353
function samplerate!(buf::AbstractSampleBuf, sr)
@@ -62,54 +62,82 @@ nchannels(arr::AbstractArray) = size(arr, 2)
6262

6363
# it's important to define Base.similar so that range-indexing returns the
6464
# right type, instead of just a bare array
65-
Base.similar{T}(buf::SampleBuf, ::Type{T}, dims::Dims) = SampleBuf(Array(T, dims), samplerate(buf))
66-
Base.similar{T}(buf::SpectrumBuf, ::Type{T}, dims::Dims) = SpectrumBuf(Array(T, dims), samplerate(buf))
65+
Base.similar(buf::SampleBuf, ::Type{T}, dims::Dims) where {T} = SampleBuf(Array{T}(dims), samplerate(buf))
66+
Base.similar(buf::SpectrumBuf, ::Type{T}, dims::Dims) where {T} = SpectrumBuf(Array{T}(dims), samplerate(buf))
6767
domain(buf::AbstractSampleBuf) = linspace(0.0, (nframes(buf)-1)/samplerate(buf), nframes(buf))
6868

6969
# There's got to be a better way to define these functions, but the dispatch
7070
# and broadcast behavior for AbstractArrays is complex and has subtle differences
7171
# between Julia versions, so we basically just override functions here as they
7272
# come up as problems
73-
import Base: .*, +, ./, -, *, /
73+
import Base: +, -, *, /
74+
import Base.broadcast
7475

76+
const ArrayIsh = Union{Array, SubArray, LinSpace, StepRangeLen}
7577
for btype in (:SampleBuf, :SpectrumBuf)
76-
for op in (:.*, :+, :./, :-)
77-
@eval function $(op)(A1::$btype, A2::$btype)
78+
# define non-broadcasting arithmetic
79+
for op in (:+, :-)
80+
@eval function $op(A1::$btype, A2::$btype)
7881
if !isapprox(samplerate(A1), samplerate(A2))
7982
error("samplerate-converting arithmetic not supported yet")
8083
end
81-
$btype($(op)(A1.data, A2.data), samplerate(A1))
84+
$btype($op(A1.data, A2.data), samplerate(A1))
8285
end
83-
@eval function $(op)(A1::$btype, A2::Union{Array, SubArray, LinSpace})
84-
$btype($(op)(A1.data, A2), samplerate(A1))
86+
@eval function $op(A1::$btype, A2::ArrayIsh)
87+
$btype($op(A1.data, A2), samplerate(A1))
8588
end
86-
@eval function $(op)(A1::Union{Array, SubArray, LinSpace}, A2::$btype)
87-
$btype($(op)(A1, A2.data), samplerate(A2))
89+
@eval function $op(A1::ArrayIsh, A2::$btype)
90+
$btype($op(A1, A2.data), samplerate(A2))
8891
end
8992
end
9093

91-
for op in (:*, :/)
92-
@eval function $(op)(A1::$btype, a2::Number)
93-
$btype($(op)(A1.data, a2), samplerate(A1))
94+
# define broadcasting application
95+
@eval function broadcast(op, A1::$btype, A2::$btype)
96+
if !isapprox(samplerate(A1), samplerate(A2))
97+
error("samplerate-converting arithmetic not supported yet")
9498
end
95-
@eval function $(op)(a1::Number, A2::$btype)
96-
$btype($(op)(a1, A2.data), samplerate(A2))
99+
$btype(broadcast(op, A1.data, A2.data), samplerate(A1))
100+
end
101+
@eval function broadcast(op, A1::$btype, A2::ArrayIsh)
102+
$btype(broadcast(op, A1.data, A2), samplerate(A1))
103+
end
104+
@eval function broadcast(op, A1::ArrayIsh, A2::$btype)
105+
$btype(broadcast(op, A1, A2.data), samplerate(A2))
106+
end
107+
@eval function broadcast(op, a1::Number, A2::$btype)
108+
$btype(broadcast(op, a1, A2.data), samplerate(A2))
109+
end
110+
@eval function broadcast(op, A1::$btype, a2::Number)
111+
$btype(broadcast(op, A1.data, a2), samplerate(A1))
112+
end
113+
@eval function broadcast(op, A1::$btype)
114+
$btype(broadcast(op, A1.data), samplerate(A1))
115+
end
116+
117+
118+
# define non-broadcast scalar arithmetic
119+
for op in (:+, :-, :*, :/)
120+
@eval function $op(A1::$btype, a2::Number)
121+
$btype($op(A1.data, a2), samplerate(A1))
122+
end
123+
@eval function $op(a1::Number, A2::$btype)
124+
$btype($op(a1, A2.data), samplerate(A2))
97125
end
98126
end
99127
end
100128

101-
typename{T, N}(::SampleBuf{T, N}) = "SampleBuf{$T, $N}"
129+
typename(::SampleBuf{T, N}) where {T, N} = "SampleBuf{$T, $N}"
102130
unitname(::SampleBuf) = "s"
103131
srname(::SampleBuf) = "Hz"
104-
typename{T, N}(::SpectrumBuf{T, N}) = "SpectrumBuf{$T, $N}"
132+
typename(::SpectrumBuf{T, N}) where {T, N} = "SpectrumBuf{$T, $N}"
105133
unitname(::SpectrumBuf) = "Hz"
106134
srname(::SpectrumBuf) = "s"
107135

108136
# from @mbauman's Sparklines.jl package
109137
const ticks = ['','','','','','','','']
110138
# 3-arg version (with explicit mimetype) is needed because we subtype AbstractArray,
111139
# and there's a 3-arg version defined in show.jl
112-
@compat function show(io::IO, ::MIME"text/plain", buf::AbstractSampleBuf)
140+
function show(io::IO, ::MIME"text/plain", buf::AbstractSampleBuf)
113141
println(io, "$(nframes(buf))-frame, $(nchannels(buf))-channel $(typename(buf))")
114142
len = nframes(buf) / samplerate(buf)
115143
ustring = unitname(buf)
@@ -122,19 +150,19 @@ function showchannels(io::IO, buf::AbstractSampleBuf, widthchars=80)
122150
# number of samples per block
123151
blockwidth = round(Int, nframes(buf)/widthchars, RoundUp)
124152
nblocks = round(Int, nframes(buf)/blockwidth, RoundUp)
125-
blocks = Array(Char, nblocks, nchannels(buf))
153+
blocks = Array{Char}(nblocks, nchannels(buf))
126154
for blk in 1:nblocks
127155
i = (blk-1)*blockwidth + 1
128156
n = min(blockwidth, nframes(buf)-i+1)
129-
peaks = maximum(abs(float(buf[(1:n)+i-1, :])), 1)
157+
peaks = maximum(abs.(float(buf[(1:n)+i-1, :])), 1)
130158
# clamp to -60dB, 0dB
131-
peaks = clamp(20log10(peaks), -60.0, 0.0)
132-
idxs = trunc(Int, (peaks+60)/60 * (length(ticks)-1)) + 1
159+
peaks = clamp.(20log10.(peaks), -60.0, 0.0)
160+
idxs = trunc.(Int, (peaks+60)/60 * (length(ticks)-1)) + 1
133161
blocks[blk, :] = ticks[idxs]
134162
end
135163
for ch in 1:nchannels(buf)
136164
println(io)
137-
print(io, convert(UTF8String, blocks[:, ch]))
165+
print(io, convert(String, blocks[:, ch]))
138166
end
139167
end
140168

@@ -221,18 +249,18 @@ end
221249

222250
# the index types that Base knows how to handle. Separate out those that index
223251
# multiple results
224-
typealias BuiltinMultiIdx Union{Colon,
225-
Vector{Int},
226-
Vector{Bool},
227-
Range{Int}}
228-
typealias BuiltinIdx Union{Int, BuiltinMultiIdx}
252+
const BuiltinMultiIdx = Union{Colon,
253+
Vector{Int},
254+
Vector{Bool},
255+
Range{Int}}
256+
const BuiltinIdx = Union{Int, BuiltinMultiIdx}
229257
# the index types that will need conversion to built-in index types. Each of
230258
# these needs a `toindex` method defined for it
231-
typealias ConvertIdx{T1 <: SIQuantity, T2 <: Int} Union{T1,
232-
# Vector{T1}, # not supporting vectors of SIQuantities (yet?)
233-
# Range{T1}, # not supporting ranges (yet?)
234-
Interval{T2},
235-
Interval{T1}}
259+
const ConvertIdx{T1 <: SIQuantity, T2 <: Int} = Union{T1,
260+
# Vector{T1}, # not supporting vectors of SIQuantities (yet?)
261+
# Range{T1}, # not supporting ranges (yet?)
262+
Interval{T2},
263+
Interval{T1}}
236264

237265
"""
238266
toindex(buf::SampleBuf, I)
@@ -242,17 +270,17 @@ indexing
242270
"""
243271
function toindex end
244272

245-
toindex{T <: Number, N}(buf::SampleBuf{T, N}, t::SecondsQuantity) = round(Int, float(t)*samplerate(buf)) + 1
246-
toindex{T <: Number, N}(buf::SpectrumBuf{T, N}, t::HertzQuantity) = round(Int, float(t)*samplerate(buf)) + 1
273+
toindex(buf::SampleBuf{T, N}, t::SecondsQuantity) where {T <: Number, N} = round(Int, float(t)*samplerate(buf)) + 1
274+
toindex(buf::SpectrumBuf{T, N}, t::HertzQuantity) where {T <: Number, N} = round(Int, float(t)*samplerate(buf)) + 1
247275

248276
# indexing by vectors of SIQuantities not yet supported
249277
# toindex{T <: SIUnits.SIQuantity}(buf::SampleBuf, I::Vector{T}) = Int[toindex(buf, i) for i in I]
250278
toindex(buf::AbstractSampleBuf, I::Interval{Int}) = I.lo:I.hi
251-
toindex{T <: SIQuantity}(buf::AbstractSampleBuf, I::Interval{T}) = toindex(buf, I.lo):toindex(buf, I.hi)
279+
toindex(buf::AbstractSampleBuf, I::Interval{T}) where {T <: SIQuantity} = toindex(buf, I.lo):toindex(buf, I.hi)
252280

253281
# AbstractArray interface methods
254282
Base.size(buf::AbstractSampleBuf) = size(buf.data)
255-
Base.linearindexing{T <: AbstractSampleBuf}(::Type{T}) = Base.LinearFast()
283+
Base.IndexStyle(::Type{T}) where {T <: AbstractSampleBuf} = Base.IndexLinear()
256284
# this is the fundamental indexing operation needed for the AbstractArray interface
257285
Base.getindex(buf::AbstractSampleBuf, i::Int) = buf.data[i];
258286

@@ -282,14 +310,14 @@ Base.ifft(buf::SpectrumBuf) = SampleBuf(ifft(buf.data), nframes(buf)/samplerate(
282310

283311
# does a per-channel convolution on SampleBufs
284312
for buftype in (:SampleBuf, :SpectrumBuf)
285-
@eval function Base.conv{T}(b1::$buftype{T, 1}, b2::$buftype{T, 1})
313+
@eval function Base.conv(b1::$buftype{T, 1}, b2::$buftype{T, 1}) where {T}
286314
if !isapprox(samplerate(b1), samplerate(b2))
287315
error("Resampling convolution not yet supported")
288316
end
289317
$buftype(conv(b1.data, b2.data), samplerate(b1))
290318
end
291319

292-
@eval function Base.conv{T, N1, N2}(b1::$buftype{T, N1}, b2::$buftype{T, N2})
320+
@eval function Base.conv(b1::$buftype{T, N1}, b2::$buftype{T, N2}) where {T, N1, N2}
293321
if !isapprox(samplerate(b1), samplerate(b2))
294322
error("Resampling convolution not yet supported")
295323
end
@@ -304,13 +332,13 @@ for buftype in (:SampleBuf, :SpectrumBuf)
304332
out
305333
end
306334

307-
@eval function Base.conv{T}(b1::$buftype{T, 1}, b2::StridedVector{T})
335+
@eval function Base.conv(b1::$buftype{T, 1}, b2::StridedVector{T}) where {T}
308336
$buftype(conv(b1.data, b2), samplerate(b1))
309337
end
310338

311-
@eval Base.conv{T}(b1::StridedVector{T}, b2::$buftype{T, 1}) = conv(b2, b1)
339+
@eval Base.conv(b1::StridedVector{T}, b2::$buftype{T, 1}) where {T} = conv(b2, b1)
312340

313-
@eval function Base.conv{T}(b1::$buftype{T, 2}, b2::StridedMatrix{T})
341+
@eval function Base.conv(b1::$buftype{T, 2}, b2::StridedMatrix{T}) where {T}
314342
if nchannels(b1) != nchannels(b2)
315343
error("Broadcasting convolution not yet supported")
316344
end
@@ -322,5 +350,5 @@ for buftype in (:SampleBuf, :SpectrumBuf)
322350
out
323351
end
324352

325-
@eval Base.conv{T}(b1::StridedMatrix{T}, b2::$buftype{T, 2}) = conv(b2, b1)
353+
@eval Base.conv(b1::StridedMatrix{T}, b2::$buftype{T, 2}) where {T} = conv(b2, b1)
326354
end

0 commit comments

Comments
 (0)