-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdistortion.jl
162 lines (146 loc) · 5.32 KB
/
distortion.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using LinearAlgebra #
using WAV
using FFTW
using DSP
using Statistics
include("adaa.jl")
#for the more imaginative distortions:
#rolling average like
function applyDistortion(signal::AbstractVector{T}, increment::Integer, distortion::Function)where
{T<:Real}
0 < increment || throw(DomainError(increment, "increment must be greater than or equal to 1"))
#signal to return
newSignal = T[]
signalLength = length(signal)
for index in 1:increment:signalLength
if index + increment > signalLength
increment = signalLength - index +1
end
block = signal[index:index+increment-1]
append!(newSignal, distortion(block))
if index == signalLength && length(newSignal) < signalLength
push!(newSignal, 80)
end
end
return newSignal
end
#clip a signal of a vector
function hardClip(signal::AbstractVector{T}, limit::T) where
{T<:Real}
0.0 <= limit <= 1.0 || throw(DomainError(limit, "limit must be between 0 and 1"))
clip(i) = (abs(i[1]) < limit && return i[1]) || return i[1] > 0 ? limit : -limit
return clip.(signal)
end
#hardClipping implented with gain/more idiomatically
function hardC(signal::Vector{Float64}, gain)::Vector{Float64}
c(x,y) = (abs(x*y) < 1 && return x*y) || return sign(x)
return c.(signal,gain)
end
function hardClipAD1(signal::Vector{Float64}, gain)::Vector{Float64}
f(x) = (abs(x) < 1 ? x : sign(x) )
f1(x) = (abs(x) < 1 ? x^2/2 : x*sign(x) - .5)
return processAD1(gain*signal, f,f1)
end
function hardClipAD2(signal::Vector{Float64}, gain)::Vector{Float64}
f(x) = (abs(x) < 1 ? x : sign(x) )
f1(x) = (abs(x) < 1 ? x^2/2 : x*sign(x) - .5)
f2(x) = (abs(x) < 1 ? x^3/6 : (x^2/2 + 1/6) * sign(x) - x/2)
return processAD2(gain*signal, f,f1,f2)
end
#softclipping of a vector. maybe latter on i'll add
#more sigmoids
function softClip(signal::AbstractVector{T}, limit)where
{T<:Real}
#as limit becomes really large function behaves like hard cliping.
#might need to check for zed
-1300.0 < limit < 13300.0 || throw(DomainError(limit, "limit must be between -1300 and 13000"))
soft(i) = tanh(limit * i)
return soft.(signal)
end
#weird movable wave shapping that i found
function chebby(signal::AbstractVector{T}, limit)where
{T<:Real}
0.0 <= limit <= 4.0 || throw(DomainError(limit, "limit must be between 0 and 4"))
cheb(x)=limit*x[1]^3+(1-limit)x[1]
return cheb.(signal)
end
function chebyshev(order,x)
if order == 0
return 0
elseif order == 1
return x
elseif order < 21
Tn_0 = Float64(1)
Tn_1 = x
Tn = Float64(0)
for n in 2:1:order
Tn = 2*x*Tn_1-Tn_0
Tn_0 = Tn_1
Tn_1= Tn
end
return Tn
else
return cos(order*acos(x))
end
end
#=gonna figure this out latter:
#supposed to return a function that represents
a weighted sum of chebbysehv polynomials
right now it will output the a lambda function in string form
=#
function poly(weights)
scale = sum(weights[2])
nomials = AbstractString["(1)", "(x[1])", "(2x[1]^2-1)",
"(4x[1]^3-3x[1])",
"(8x[1]^4[1]-8x[1]^2+1)",
"(16x[1]^5-20x[1]^3+5x[1])",
"(32x[1]^6-48x[1]^4+18x[1]^2-1))",
"(64x[1]^7-112x[1]^5+56x[1]^3-7x[1])"]
func = "x-> "
for i in 1:length(weights[1]) func *= nomials[i] *= "*$(weights[2][i])/$scale + "
end
func = func[1:length(func)-2]
return func
end
#first four chebby polynomials weighted
function cheb(signal::AbstractVector)
ch(val)= ((4 * val^3 - 3 * val) + (2 * val^2 - 1) + val + 1)/4
return ch.(signal)
end
#=moving average filter but worse:
# perhaps interested for percussive elements?
=#
function fakebitcrush(signal::AbstractVector{T}, rate::Integer) where
{T<:Real}
1 < rate <= length(signal)/rate ||
throw(DomainError(rate, "rate must be between 0 and length(signal)/100"))
bit(block) = mean(block)*ones(length(block))
return applyDistortion(signal, rate, bit)
end
function linear(block)#linear regression
linreg(x,y) = hcat(ones(size(y, 1)), y) \ x
timeVector = range(0.0, step=inv(41000), length=length(block))
return linreg(block,timeVector)
end
#=replaces partition amount of samples with linear approximation
sounds like a combo of bitcrush and lpf applied to random noise.
pretty cool
=#
function linearDistortion(signal::AbstractVector{T}, partition::Integer) where
{T<:Real}
0 < partition || throw(DomainError(iterations, "partition must be greater than or equal to 1"))
#applies best fit apprx
f(y,x) = y[2] .* x .+ y[1]
line(block) = f(linear(block),range(0.0, step=inv(41000), length=length(block)))
applyDistortion(signal, partition,line)
end
#= replace partition samples with the sample samples but sorted
ascending or decending based on the linear regression of said partition()
similar to linearDistortion, but more intense
=#
function sortDistortion(signal::AbstractVector{T}, partition::Integer) where
{T<:Real}
0 < partition || throw(DomainError(iterations, "partition must be greater than or equal to 1"))
sorting(block) = linear(block)[2] > 0 ? sort(block) : sort(block,rev=true)
return applyDistortion(signal, partition, sorting)
end