def make_plot_of_meas_file(meas_file):
    # read audio file
    fs, x = wavfile.read(meas_file)
    x = adsp.normalize(x)

    # make plot
    fig = Figure()
    axis = fig.add_subplot(1, 1, 1)
    axis.set_title("Original Audio")
    axis.set_xlabel("Time [seconds]")
    axis.plot(np.arange(len(x)) / fs, x)
    
    # Convert plot to PNG image
    pngImage = io.BytesIO()
    FigureCanvas(fig).print_png(pngImage)
    
    # Encode PNG image to base64 string
    pngImageB64String = "data:image/png;base64,"
    pngImageB64String += base64.b64encode(pngImage.getvalue()).decode('utf8')
    return pngImageB64String
Beispiel #2
0
def plot_freqz_mag(w, H, norm=False):
    """Plots the magnitude output of the scipy.signal.freqz function

    Parameters
    ----------
    w :  ndarray
        w output of freqz
    H : ndarray
        H output of freqz
    norm : bool, optional
        Should normalize the magnitude response
    """
    if norm:
        H = adsp.normalize(H)

    plot = plt.semilogx(w, 20 * np.log10(np.abs(H)))
    plt.gca().xaxis.set_major_formatter(ticker.ScalarFormatter())
    plt.ylabel('Magnitude [dB]')
    plt.xlabel('Frequency [Hz]')
    return plot
Beispiel #3
0
    def process_measurement(self, measurement):
        """
        Processes a measurement made using the probe signal
        for this object.
        """
        self.far_response = adsp.normalize(
            signal.convolve(measurement, self.inv_probe))

        amax = np.argmax(self.far_response)
        level = adsp.level_detect(self.far_response, self.fs)
        off = int(self.fs / 10)
        amin = np.argwhere(level[amax - off:amax] < 0.05)[-1][0]
        amax = amax - (off - amin)
        end = amax + np.argwhere(level[amax:] < 10**(-60 / 20))[0][0]

        self.harm_responses = [self.far_response[amax:end]]
        for i in range(1, len(self.harm_times)):
            start = amax - self.harm_times[i]
            end = amax - self.harm_times[i - 1]
            self.harm_responses.append(self.far_response[start:end])
Beispiel #4
0
def filt_mode(x, freq, fs, width, order=4):
    """
    Filter the signal around a mode frequency

    Parameters
    ----------
    x : ndarray
        The original signal
    freq : float
        The mode frequency to filter out
    fs : float
        The sample rate of the signal
    width : float
        The width of frequencies around the mode to filter
    order : int, optional
        The order of filter to use

    Returns
    -------
    x_filt : ndarray
        The signal filtered around the mode frequency
    """
    lowFreq = freq - width / 2
    b_hpf = np.array([1.0, 0.0, 0.0])
    a_hpf = np.array([1.0, 0.0, 0.0])
    if lowFreq > 0.1:
        Wn = lowFreq / (fs / 2)
        b_hpf, a_hpf = signal.butter(order, Wn, btype='highpass', analog=False)

    highFreq = freq + width / 2
    b_lpf = np.array([1.0, 0.0, 0.0])
    a_lpf = np.array([1.0, 0.0, 0.0])
    if highFreq < fs / 2:
        Wn = highFreq / (fs / 2)
        b_lpf, a_lpf = signal.butter(order, Wn, btype='lowpass', analog=False)

    x_filt = adsp.normalize(
        signal.lfilter(b_hpf, a_hpf, (signal.lfilter(b_lpf, a_lpf, x))))
    return x_filt
b, a = adsp.design_LPF2 (1000, 10, fs)

sweep = adsp.sweep_log (20, 22000, 1, fs)

legend = []
freqs = np.logspace (1, 3.4, num=1000, base=20)
for g in [0.00001, 0.04, 0.2, 1.0]:
    cur_sweep = np.copy (sweep) * g
    y = np.copy (cur_sweep)

    filter = NLFeedback()
    filter.setCoefs (b, a)
    filter.fb_lambda = lambda a,x : a*np.tanh (x)
    y = filter.process_block (y)

    h = adsp.normalize (adsp.sweep2ir (cur_sweep, y))
    adsp.plot_magnitude_response (h, [1], worN=freqs, fs=fs)

    if g < 0.0001: legend.append ('Linear')
    else: legend.append ('Nonlinear (gain={})'.format (g))

plt.title ('Lowpass Filter with nonlinear feedback')
plt.legend (legend)
plt.ylim (-10)

#%% [markdown]
# From the above plot, it seems pretty obvious that as the gain of the input
# signal increases, the resonant frequency of the filter seems to shift
# as well. Vadim Zavalishin describes a similar effect that occurs when
# adding nonlinear elements to the feedback paths of a ladder filter, and
# he has a useful way of thinking about this phenomenon: "as audio-rate
    plt.ylabel('Frequency [Hz]')
    plt.gca().yaxis.set_major_formatter(ticker.ScalarFormatter())
    plt.ylim(100, 16000)
    plt.yscale('log')
    plt.title(title)
    # plt.plot(x)


# %%
files = []
# files.append({'file': 'DAFX/full_model',  'title': 'DAFx Full Model'})
# files.append({'file': 'DAFX/full_actual', 'title': 'DAFx Full Recorded'})
files.append({
    'file': 'HydroFlask/full_model',
    'title': 'HydroFlask Full Model'
})
files.append({
    'file': 'HydroFlask/full_actual',
    'title': 'HydroFlask Full Recorded'
})

N = 60000
for f in files:
    fs, x = wavfile.read('Audio/{}.wav'.format(f['file']))
    x = adsp.normalize(x[:N])
    plot_specgram(x, fs, title=f['title'])
    plt.savefig('Figures/Specgrams/{}.png'.format(f['title']))

# %%
plt.show()
def write_to_file(x, y, name):
    wavfile.write('Audio/{}_model.wav'.format(name), __fs__, adsp.normalize(y))
    wavfile.write('Audio/{}_actual.wav'.format(name), __fs__, adsp.normalize(x))
Beispiel #8
0
NUM_FILES = 1600
NUM_SAMPLES = 16000
QUIET_THRESH = NUM_SAMPLES / 100
clean_data = []
fs_data = []
for i in tqdm(range(NUM_FILES)):
    fs = np.random.uniform(88000, 192000)
    x = load_fma_file(files, filepath, fs, NUM_SAMPLES)

    # skip if too quiet
    if np.sum(np.abs(x)) < QUIET_THRESH:
        i -= 1
        continue

    fs_data.append(np.ones_like(x) * (1.0 / fs))
    clean_data.append(adsp.normalize(x))

clean_data = np.asarray(clean_data)

# %%
# look at file
idx = 8
plt.plot(clean_data[idx])

# %%
hyst_data = []
drive_data = []
sat_data = []
width_data = []
for i, x in tqdm(enumerate(clean_data)):
    fs = 1.0 / fs_data[i][0]
Beispiel #9
0
import os, sys

sys.path.append(os.path.abspath('crossroads_scripts'))
from evolve_structure import get_evolved_structure
from param_estimation import get_error_for_model

import numpy as np
from scipy.io import wavfile
import scipy.signal as signal
import audio_dspy as adsp
import random

# read file
fs, x = wavfile.read('audio_files/drums.wav')
x = adsp.normalize(x)

ys = []
names = []


def add_to_tests(name, y, ys, names):
    ys.append(y)
    names.append(name)
    wavfile.write('audio_files/' + names[-1] + '.wav', fs, y)


# Gain
gain = -0.2
y1 = gain * x
add_to_tests('gain', y1, ys, names)
Beispiel #10
0
BANDWIDTH = 200
freqs = np.arange(BANDWIDTH / 2, 22000, BANDWIDTH)

# Analyze original signal
times = find_decay_times(freqs, x, fs, BANDWIDTH, thresh=-30, dBTime=-45)

time_peaks, _ = signal.find_peaks(times)
freq_widths, _, _, _ = signal.peak_widths(times, time_peaks)
print(freqs[time_peaks])
print(BANDWIDTH * freq_widths)

plt.figure()
f, t, Sxx = signal.spectrogram(x, fs)
plt.pcolormesh(t,
               f,
               20 * np.log10(np.abs(adsp.normalize(Sxx))),
               cmap='inferno',
               vmin=-180)
# plt.plot(times, freqs, 'r')
plt.xlim(0, 1.6)

# Filter spec
filter_freq = freqs[time_peaks[0]]
filterQ = filter_freq / (BANDWIDTH * freq_widths[0])
print(filterQ)

original_decay_time = find_decay_time(filter_freq,
                                      x,
                                      fs,
                                      BANDWIDTH * freq_widths[0],
                                      thresh=-30)
Beispiel #11
0
# %%
import numpy as np
import scipy.signal as signal
import matplotlib.pyplot as plt
import audio_dspy as adsp

# %%
N = 500
fs = 44100
freq = 2000
x = np.sin(2 * np.pi * freq / fs * np.arange(N))

plt.plot(x)

# %%
X = 20 * np.log10(adsp.normalize(np.abs(np.fft.rfft(x))))
plt.plot(X)

# %%
eq = adsp.EQ(fs)
Qs = adsp.butter_Qs(6)
print(Qs)
eq.add_LPF(1500, Qs[0])
eq.add_LPF(1500, Qs[1])
eq.add_LPF(1500, Qs[2])


def get_square_half_freq(sig):
    y = np.copy(sig)

    rising = True
# b, a = design_allpole (mags, poles, fs=fs)

#%%
freqs = np.logspace(1, 3.4, num=1000, base=20)
for g in [0.00001, 0.001, 0.01, 0.1, 0.5, 0.8]:
    cur_sweep = np.copy(sweep) * g
    y = np.copy(cur_sweep)

    filter = Biquad()
    b, a = adsp.design_bell(1000, 0.707, 2, fs)
    filter.setCoefs(b, a)
    # filter.set_coefs (a)
    filter.fb_lambda = lambda a, x: a * np.tanh(x)  # adsp.soft_clipper (x)
    y = filter.process_block(y)

    h = adsp.normalize(adsp.sweep2ir(cur_sweep, y))
    adsp.plot_magnitude_response(h, [1], worN=freqs, fs=fs)

# plt.ylim (-15)

#%%
filter = AllPole()
filter.set_coefs(a)
filter.fb_lambda = lambda a, x: a * adsp.soft_clipper(x)
y = filter.process_block(y)

#%%
ylin = np.copy(sweep)

filter_lin = AllPole()
filter_lin.set_coefs(a)
Beispiel #13
0
# where "WF" denotes the wavefolding nonlinearity. For the gain "G",
# I typically use somwhere between -0.5 and -0.1. Below we show the
# static curve and sine wave response for a saturating wavefolder
# with a hyperbolic tangent saturator, a sine wavefolder, and G=-0.2.


# %%
def sine_tanh(x, G, freq, fs):
    return np.tanh(x) + G * sine_wave(x, freq, fs)


plt.figure()
adsp.plot_static_curve(lambda x: sine_tanh(x, -0.2, fs / 2, fs), gain=5)
plt.title('Saturating Wavefolder Static Curve')

y3 = adsp.normalize(sine_tanh(3 * x, -0.2, fs / 2.5, fs))

plt.figure()
plt.plot(x)
plt.plot(y)
plt.plot(y3)
plt.legend(['Dry', 'Wavefolder', 'Saturating Wavefolder'])
plt.title('Wavfolder vs. Saturating Wavefolder')

# %% [markdown]
# While the modified structure may seem only marginally different from the
# original wavefolder, watch how the response changes for a large input:

# %%
N = fs / 50
n = np.arange(N)
Beispiel #14
0
# to read this insightful and humorous article on the subject from
# Howard Johnson [[link](https://www.edn.com/electronics-blogs/signal-integrity/4363408/7-solution)].

# %% 
def trunc_gauss(x, mu, sig, start, end):
    y = np.zeros(len(x))
    ind = np.argwhere(np.logical_and(np.abs(x-mu) < end, np.abs(x-mu) > start))
    y[ind] = norm.pdf(x[ind], mu, sig)
    return y

R = 1000
diff = 200
tol_low = 0.05
tol_high = 0.1
x = np.arange(R-diff, R+diff, 0.1)
y = adsp.normalize(trunc_gauss(x, R, 50, R*tol_low, R*tol_high))
plt.plot(x, y)

plt.xlabel('Resistance [Ohms]')
plt.ylabel('Probability')
plt.title('Probability Distribution of 1 kOhm Resistor with 10% tolerance')

# %% [markdown]
# Now we can see what our new frequency responses should look like with our
# updated component value distribution.


# %%
def getCompVal2(val, tol_low, tol_high):
    if tol_high == 0:
        return val