update 2
This commit is contained in:
parent
bf22e5a326
commit
4437abc01d
10 changed files with 21 additions and 42 deletions
|
@ -45,7 +45,7 @@ def test_filter(ff, A=toA(12), Q=toQ(1), **kwargs):
|
||||||
|
|
||||||
npc = [makemag(*f) for f in cascades['raw']]
|
npc = [makemag(*f) for f in cascades['raw']]
|
||||||
def neonpink(xs):
|
def neonpink(xs):
|
||||||
print("neonpink(): DEPRECATED")
|
lament("neonpink(): DEPRECATED.")
|
||||||
combined = np.zeros(len(xs))
|
combined = np.zeros(len(xs))
|
||||||
for f in npc:
|
for f in npc:
|
||||||
combined += f(xs)
|
combined += f(xs)
|
||||||
|
|
|
@ -12,6 +12,7 @@ HP1 = lambda A, Q: ((1,0),(1,1))
|
||||||
LS1 = lambda A, Q: ((1,A),(1,1/A))
|
LS1 = lambda A, Q: ((1,A),(1,1/A))
|
||||||
HS1 = lambda A, Q: ((A,1),(1/A,1))
|
HS1 = lambda A, Q: ((A,1),(1/A,1))
|
||||||
|
|
||||||
|
# patterns observed, in case some simplification could be done:
|
||||||
# a always gets divided by A instead of multiplied
|
# a always gets divided by A instead of multiplied
|
||||||
# b1 and a1 always /= Q
|
# b1 and a1 always /= Q
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
def LPB(n):
|
def LPB(n):
|
||||||
# crap ripped from https://github.com/vinniefalco/DSPFilters/blob/master/shared/DSPFilters/source
|
# via https://github.com/vinniefalco/DSPFilters/blob/master/shared/DSPFilters/source
|
||||||
"""n-th degree butterworth low-pass filter cascade
|
"""n-th degree butterworth low-pass filter cascade
|
||||||
|
|
||||||
-3 dB at center frequency."""
|
-3 dB at center frequency."""
|
||||||
|
@ -23,7 +23,7 @@ def LPB(n):
|
||||||
return series
|
return series
|
||||||
|
|
||||||
def LPC(n, ripple, type=1):
|
def LPC(n, ripple, type=1):
|
||||||
# crap ripped from https://github.com/vinniefalco/DSPFilters/blob/master/shared/DSPFilters/source
|
# via https://github.com/vinniefalco/DSPFilters/blob/master/shared/DSPFilters/source
|
||||||
# FIXME: type 2 has wrong center frequency?
|
# FIXME: type 2 has wrong center frequency?
|
||||||
"""n-th degree chebyshev low-pass filter cascade
|
"""n-th degree chebyshev low-pass filter cascade
|
||||||
|
|
||||||
|
@ -84,4 +84,3 @@ def LPC(n, ripple, type=1):
|
||||||
den = (1/-real, 1)
|
den = (1/-real, 1)
|
||||||
series += [(num, den)]
|
series += [(num, den)]
|
||||||
return series
|
return series
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ from .bq import *
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
# as calculated by LPB in butterworth.py
|
||||||
_bq2a = 1/.76536686473017945
|
_bq2a = 1/.76536686473017945
|
||||||
_bq2b = 1/1.8477590650225735
|
_bq2b = 1/1.8477590650225735
|
||||||
_bq2a_bw = isqrt2/_bq2a
|
_bq2a_bw = isqrt2/_bq2a
|
||||||
|
@ -17,6 +18,7 @@ cascades = {
|
||||||
'raw': [
|
'raw': [
|
||||||
nf(LP1, 20, 0, 1, 29),
|
nf(LP1, 20, 0, 1, 29),
|
||||||
nf(HS1, 800, 12, 1, 0),
|
nf(HS1, 800, 12, 1, 0),
|
||||||
|
# i don't use the exact _bq2 coeffecients here for legacy reasons
|
||||||
( 45, HP2( 0, 1.32), 0.5), # roughly estimates
|
( 45, HP2( 0, 1.32), 0.5), # roughly estimates
|
||||||
( 45, HP2( 0, 0.54), 0.5), # a 4-pole butterworth highpass
|
( 45, HP2( 0, 0.54), 0.5), # a 4-pole butterworth highpass
|
||||||
nf(LP2, 14000, 0, 1.33, 0),
|
nf(LP2, 14000, 0, 1.33, 0),
|
||||||
|
@ -41,7 +43,7 @@ cascades = {
|
||||||
],
|
],
|
||||||
# here's the ideas written out:
|
# here's the ideas written out:
|
||||||
# low (<40) freqs dont contribute much to ears (feel doesnt count.)
|
# low (<40) freqs dont contribute much to ears (feel doesnt count.)
|
||||||
# high (>14000) freqs are mostly unheard. 14000 is the top for someone with bad hearing.
|
# high (>14000) freqs are mostly unheard.
|
||||||
# 750 Hz isn't too painful to the ears, but cutting them would give
|
# 750 Hz isn't too painful to the ears, but cutting them would give
|
||||||
# overly-produced songs not enough gain to hear vocals, so keep it flat.
|
# overly-produced songs not enough gain to hear vocals, so keep it flat.
|
||||||
# we're supposedly less sensitive to 1400 Hz, but i need to
|
# we're supposedly less sensitive to 1400 Hz, but i need to
|
||||||
|
@ -60,7 +62,7 @@ cascades = {
|
||||||
( 40, HP2(0, toQ(1.00)), 0.0),
|
( 40, HP2(0, toQ(1.00)), 0.0),
|
||||||
(10000, LP1(0, 0), 0.0),
|
(10000, LP1(0, 0), 0.0),
|
||||||
],
|
],
|
||||||
# tested against your 227 top-rated songs
|
# average curve of my 227 favorite songs
|
||||||
'np2': [
|
'np2': [
|
||||||
nf(LP1, 20, 0, 1, 32),
|
nf(LP1, 20, 0, 1, 32),
|
||||||
nf(HS1, 800, 9, 1, -4.5),
|
nf(HS1, 800, 9, 1, -4.5),
|
||||||
|
@ -70,7 +72,7 @@ cascades = {
|
||||||
nf(LS2, 38, -9, 1.00, 0),
|
nf(LS2, 38, -9, 1.00, 0),
|
||||||
nf(PE2, 64, 4.5, 1.20, 0),
|
nf(PE2, 64, 4.5, 1.20, 0),
|
||||||
],
|
],
|
||||||
# side channel
|
# same but for the side channel
|
||||||
'np2s': [
|
'np2s': [
|
||||||
nf(LP1, 20, 0, 1, 32),
|
nf(LP1, 20, 0, 1, 32),
|
||||||
nf(HS1, 800, 9, 1, -4.5),
|
nf(HS1, 800, 9, 1, -4.5),
|
||||||
|
|
|
@ -30,11 +30,11 @@ def magnitudes(s, size=8192):
|
||||||
for i in range(0, L - 1, int(step)):
|
for i in range(0, L - 1, int(step)):
|
||||||
windowed = s[i:i+win_size]*win
|
windowed = s[i:i+win_size]*win
|
||||||
power = np.abs(rfft(windowed, size))**2
|
power = np.abs(rfft(windowed, size))**2
|
||||||
# this scraps the nyquist value to get exactly size outputs
|
# this scraps the nyquist value to get exactly 'size' outputs
|
||||||
yield power[0:size]
|
yield power[0:size]
|
||||||
count += 1
|
count += 1
|
||||||
|
|
||||||
#assert(segs == count)
|
#assert(segs == count) # this is probably no good in a generator
|
||||||
|
|
||||||
def averfft(s, size=8192):
|
def averfft(s, size=8192):
|
||||||
"""calculates frequency magnitudes by fft and averages them together."""
|
"""calculates frequency magnitudes by fft and averages them together."""
|
||||||
|
|
|
@ -5,6 +5,8 @@ import sympy as sym
|
||||||
|
|
||||||
def zcgen_py(n, d):
|
def zcgen_py(n, d):
|
||||||
zcs = np.zeros(d + 1)
|
zcs = np.zeros(d + 1)
|
||||||
|
|
||||||
|
# expanded from the equation in zcgen_sym
|
||||||
zcs[0] = 1
|
zcs[0] = 1
|
||||||
for _ in range(n):
|
for _ in range(n):
|
||||||
for i in range(d, 0, -1):
|
for i in range(d, 0, -1):
|
||||||
|
|
|
@ -4,7 +4,6 @@ from matplotlib import ticker
|
||||||
def response_setup(ax, ymin=-24, ymax=24, yL=ticker.AutoMinorLocator(3)):
|
def response_setup(ax, ymin=-24, ymax=24, yL=ticker.AutoMinorLocator(3)):
|
||||||
ax.set_xlim(20, 20000)
|
ax.set_xlim(20, 20000)
|
||||||
ax.set_ylim(ymin, ymax)
|
ax.set_ylim(ymin, ymax)
|
||||||
#ax.set_yticks(np.arange(ymin, ymax + 1, 6))
|
|
||||||
ax.set_yticks(tuple(range(ymin, ymax + 1, 6)))
|
ax.set_yticks(tuple(range(ymin, ymax + 1, 6)))
|
||||||
ax.yaxis.set_minor_locator(yL)
|
ax.yaxis.set_minor_locator(yL)
|
||||||
ax.grid(True, 'both')
|
ax.grid(True, 'both')
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
from . import xsp
|
from . import xsp, lament
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
def smoothfft(xs, ys, bw=1, precision=512):
|
def smoothfft(xs, ys, bw=1, precision=512):
|
||||||
"""performs log-lin smoothing on magnitude data,
|
"""performs log-lin smoothing on magnitude data,
|
||||||
generally from the output of averfft."""
|
generally from the output of averfft."""
|
||||||
# TODO: option to extrapolate (pad) fft data
|
lament("smoothfft(): DEPRECATED; use smoothfft2 instead.")
|
||||||
xs2 = xsp(precision)
|
xs2 = xsp(precision)
|
||||||
ys2 = np.zeros(precision)
|
ys2 = np.zeros(precision)
|
||||||
log_xs = np.log(xs)
|
log_xs = np.log(xs)
|
||||||
for i, x in enumerate(xs2):
|
for i, x in enumerate(xs2):
|
||||||
dist = np.exp(np.abs(log_xs - np.log(x + 1e-35)))
|
dist = np.exp(np.abs(log_xs - np.log(x + 1e-35)))
|
||||||
window = np.maximum(0, 1 - (dist - bw))
|
window = np.maximum(0, 1 - (dist - bw))
|
||||||
# at this point you could probably
|
# at this point we could probably
|
||||||
# normalize our *triangular* window to 0-1
|
# normalize our *triangular* window to 0-1
|
||||||
# and transform it into *another* windowing function
|
# and transform it into *another* windowing function
|
||||||
wsum = np.sum(window)
|
wsum = np.sum(window)
|
||||||
|
@ -25,7 +25,7 @@ def smoothfft2(xs, ys, bw=1, precision=512, compensate=True):
|
||||||
ys2 = np.zeros(precision)
|
ys2 = np.zeros(precision)
|
||||||
log2_xs2 = np.log2(xs2)
|
log2_xs2 = np.log2(xs2)
|
||||||
for i, x in enumerate(xs):
|
for i, x in enumerate(xs):
|
||||||
#dist = np.abs(np.log2(xs2/(x + 1e-35)))/bw
|
# before optimizations: dist = np.abs(np.log2(xs2/(x + 1e-35)))/bw
|
||||||
dist = np.abs(log2_xs2 - np.log2(x + 1e-35))/bw
|
dist = np.abs(log2_xs2 - np.log2(x + 1e-35))/bw
|
||||||
#window = np.maximum(0, 1 - dist) # triangle window
|
#window = np.maximum(0, 1 - dist) # triangle window
|
||||||
window = np.exp(-dist**2/(0.5/2)) # gaussian function (non-truncated)
|
window = np.exp(-dist**2/(0.5/2)) # gaussian function (non-truncated)
|
||||||
|
@ -34,27 +34,3 @@ def smoothfft2(xs, ys, bw=1, precision=512, compensate=True):
|
||||||
_, temp = smoothfft2(xs, np.ones(len(xs)), bw=bw, precision=precision, compensate=False)
|
_, temp = smoothfft2(xs, np.ones(len(xs)), bw=bw, precision=precision, compensate=False)
|
||||||
ys2 /= temp
|
ys2 /= temp
|
||||||
return xs2, ys2
|
return xs2, ys2
|
||||||
|
|
||||||
def smoothfft3(xs, ys, bw=1, precision=1024):
|
|
||||||
# actually this will never work...
|
|
||||||
# you need to go back to smoothfft2,
|
|
||||||
# which technically works as-designed,
|
|
||||||
# and fix the compensation to work with widely-spaced data.
|
|
||||||
raise Exception("smoothfft3 is broken.")
|
|
||||||
xs2 = xsp(precision)
|
|
||||||
ys2 = np.zeros(precision)
|
|
||||||
step = (xs[1] - xs[0])
|
|
||||||
if True:
|
|
||||||
for i, x in enumerate(xs):
|
|
||||||
dist = np.abs(xs2 - x)
|
|
||||||
bw2 = x*bw/2
|
|
||||||
window = np.maximum(0, 1 - dist/bw2)
|
|
||||||
#window = np.minimum(1, np.maximum(0, 1 - (dist - bw)))
|
|
||||||
ys2 += ys[i]*window
|
|
||||||
else:
|
|
||||||
for i, x2 in enumerate(xs2):
|
|
||||||
dist = np.abs(xs - x2)
|
|
||||||
window = np.maximum(0, 1 - (dist/step/bw))
|
|
||||||
wsum = np.sum(window)
|
|
||||||
ys2[i] = np.sum(ys*window/wsum)
|
|
||||||
return xs2, ys2
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ def tsp(N, m=0.5):
|
||||||
# http://www.sound.sie.dendai.ac.jp/dsp/e-21.html
|
# http://www.sound.sie.dendai.ac.jp/dsp/e-21.html
|
||||||
|
|
||||||
if m < 0 or m > 1:
|
if m < 0 or m > 1:
|
||||||
raise Exception("sdfgsdfgsdg")
|
raise Exception("what are you doinggg")
|
||||||
|
|
||||||
if N < 0:
|
if N < 0:
|
||||||
raise Exception("The number of length must be the positive number")
|
raise Exception("The number of length must be the positive number")
|
||||||
|
|
|
@ -6,7 +6,7 @@ import scipy.io.wavfile as wav
|
||||||
import ewave
|
import ewave
|
||||||
|
|
||||||
def wav_smart_read(fn):
|
def wav_smart_read(fn):
|
||||||
lament('DEPRECATED: wav_smart_read; use wav_read instead')
|
lament('wav_smart_read(): DEPRECATED; use wav_read instead.')
|
||||||
srate, s = wav.read(fn)
|
srate, s = wav.read(fn)
|
||||||
if s.dtype != np.float64:
|
if s.dtype != np.float64:
|
||||||
bits = s.dtype.itemsize*8
|
bits = s.dtype.itemsize*8
|
||||||
|
@ -14,7 +14,7 @@ def wav_smart_read(fn):
|
||||||
return srate, s
|
return srate, s
|
||||||
|
|
||||||
def wav_smart_write(fn, srate, s):
|
def wav_smart_write(fn, srate, s):
|
||||||
lament('DEPRECATED: wav_smart_write')
|
lament('wav_smart_write(): DEPRECATED; use ewave instead.')
|
||||||
si = np.zeros_like(s, dtype='int16')
|
si = np.zeros_like(s, dtype='int16')
|
||||||
bits = si.dtype.itemsize*8
|
bits = si.dtype.itemsize*8
|
||||||
si += np.clip(s*2**(bits - 1), -32768, 32767)
|
si += np.clip(s*2**(bits - 1), -32768, 32767)
|
||||||
|
|
Loading…
Reference in a new issue