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
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
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])
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))
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]
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)
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)
# %% 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)
# 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)
# 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