def get_bin_f0_B(bin_initial_estimate, fft_buffers, noise_cutoff, bin_spread_below, bin_spread_above, fs): ### gradually discover/refine estimates of bin_f0 and B bin_f0 = bin_initial_estimate B = 0.0 limit = defs.TOTAL_HARMONICS for i in range(defs.B_INITIAL_PARTIALS, defs.TOTAL_HARMONICS): #print fft_buffers.shape bin_f0, B, rsquared, ok = align_with_B(i, bin_f0, B, fft_buffers, noise_cutoff, bin_spread_below, bin_spread_above, fs) #print B, rsquared limit = stiff_ideal_conflict.find_limit(bin_f0, B, bin_spread_below, bin_spread_above) #print B, rsquared, limit if i > limit: ok = False #print "%i\t%.2f\t%.2e\t\t%i\t%i" % ( # i, bin_f0, B, ok, lim) if ok is False: break rows, columns = fft_buffers.shape partialss = [] idealss = [] for j in range(rows): fft = fft_buffers[j] harmonics, ideal_harmonics = partials.get_freqs_mags(defs.TOTAL_HARMONICS, bin_f0, B, fft, bin_spread_below, bin_spread_above, only_peaks=True, Bsearch=True) harmonics = [ h for h in harmonics if h.mag > noise_cutoff[h.fft_bin] ] ideal_harmonics = [ h for h in ideal_harmonics if h.mag > noise_cutoff[h.fft_bin] ] partialss.extend(harmonics) idealss.extend(ideal_harmonics) if False: pylab.figure() ns = [ h.n for h in partialss if h.n > defs.B_MIN_HARMONIC_FIT_TO ] pylab.plot( ns, [ h.fft_bin - partials.mode_B2freq(bin_f0, h.n, B) for h in partialss if h.n > defs.B_MIN_HARMONIC_FIT_TO ], '.') pylab.show() if defs.B_PLOT_FIT: ns = [ h.n for h in partialss if h.n > defs.B_MIN_HARMONIC_FIT_TO ] ys = [ h.fft_bin / h.n for h in partialss if h.n > defs.B_MIN_HARMONIC_FIT_TO ] omit_ns = [ h.n for h in partialss if h.n <= defs.B_MIN_HARMONIC_FIT_TO ] omit_ys = [ h.fft_bin / h.n for h in partialss if h.n <= defs.B_MIN_HARMONIC_FIT_TO ] plots.plot_B_fit(ns, ys, omit_ns, omit_ys, bin_f0, B, fs, idealss) pylab.show() return bin_f0, B, rsquared, partialss, limit
def plot_stiff_area(bin_f0, B, bin_spread_below, bin_spread_above, stiff_partials, sample_rate): stiff_bins = numpy.array([ partials.mode_B2freq(bin_f0, i + 1, B) for i in xrange(len(stiff_partials)) ]) for i, est in enumerate(stiff_bins): low = stft.bin2hertz(est - bin_spread_below, sample_rate) high = stft.bin2hertz(est + bin_spread_above, sample_rate) if i == 0: pylab.axvspan(low, high, color='c', alpha=0.3, label="stiff") else: pylab.axvspan(low, high, color='c', alpha=0.3)
def plot_stiff_area(bin_f0, B, bin_spread_below, bin_spread_above, stiff_partials, sample_rate): stiff_bins = numpy.array( [ partials.mode_B2freq( bin_f0, i+1, B) for i in xrange(len(stiff_partials)) ] ) for i, est in enumerate(stiff_bins): low = stft.bin2hertz(est - bin_spread_below, sample_rate) high = stft.bin2hertz(est + bin_spread_above, sample_rate) if i == 0: pylab.axvspan(low, high, color='c', alpha=0.3, label="stiff") else: pylab.axvspan(low, high, color='c', alpha=0.3)
def plot_B_fit(ns, ys, omit_ns, omit_ys, bin_f0, B, sample_rate, idealss): x = numpy.arange(1, max(ns)+1) predicted = partials.mode_B2freq(bin_f0, x, B) / x ideal_below = partials.mode_B2freq(bin_f0, x, 0) / x ideal_above = ((partials.mode_B2freq(bin_f0, x+1, 0) ) / x / bin_f0) below_bins = int(stft.hertz2bin(bin_f0*defs.B_PEAK_SPREAD_BELOW_HERTZ, sample_rate)) above_bins = int(stft.hertz2bin(bin_f0*defs.B_PEAK_SPREAD_ABOVE_HERTZ, sample_rate)) ideal_above_safe = ((partials.mode_B2freq(bin_f0, x+1, 0) - below_bins - above_bins ) / x / bin_f0) ideal_above_semi_stiff = ((partials.mode_B2freq(bin_f0, x+1, B/4.0) ) / x / bin_f0) ideal_above_above = ((partials.mode_B2freq(bin_f0, x+2, 0) - above_bins ) / x / bin_f0) ideal_ns = numpy.array([ h.n for h in idealss ]) ideal_ys = [ h.fft_bin / h.n for h in idealss ] ideal_ns_next = ideal_ns-1 ideal_ys_next = [ h.fft_bin / (h.n-1) for h in idealss ] ysa = numpy.array(ys) pylab.figure() pylab.plot(ns, ysa, '.') numpy.savetxt("ns_ys.txt", numpy.vstack(( numpy.array(ns), stft.bin2hertz(numpy.array(ysa), sample_rate) )).transpose()) pylab.plot(ideal_ns, ideal_ys, '.', color="green") pylab.plot(ideal_ns_next, ideal_ys_next, '.', color="green") pylab.plot(x, predicted, '-') numpy.savetxt("ns_predicted.txt", numpy.vstack(( numpy.array(x), stft.bin2hertz(numpy.array(predicted), sample_rate) )).transpose()) pylab.plot(x, ideal_below, '-', color="orange") pylab.plot(x, ideal_above_safe, '-', color="pink") pylab.plot(x, ideal_above, '-', color="orange") #pylab.plot(x, ideal_above_above, '-', color="orange") #pylab.plot(x, ideal_above_semi_stiff, '-', color="orange") pylab.plot( omit_ns, omit_ys, 'rx') numpy.savetxt("omit_ns_ys.txt", numpy.vstack(( numpy.array(omit_ns), stft.bin2hertz(numpy.array(omit_ys), sample_rate) )).transpose()) #pylab.plot(xs, weights, 'o') pylab.xlim(0) pylab.ylim([0.99*min(ys), 1.01*max(ys)])
def plot_B_fit(ns, ys, omit_ns, omit_ys, bin_f0, B, sample_rate, idealss): x = numpy.arange(1, max(ns) + 1) predicted = partials.mode_B2freq(bin_f0, x, B) / x ideal_below = partials.mode_B2freq(bin_f0, x, 0) / x ideal_above = ((partials.mode_B2freq(bin_f0, x + 1, 0)) / x / bin_f0) below_bins = int( stft.hertz2bin(bin_f0 * defs.B_PEAK_SPREAD_BELOW_HERTZ, sample_rate)) above_bins = int( stft.hertz2bin(bin_f0 * defs.B_PEAK_SPREAD_ABOVE_HERTZ, sample_rate)) ideal_above_safe = ( (partials.mode_B2freq(bin_f0, x + 1, 0) - below_bins - above_bins) / x / bin_f0) ideal_above_semi_stiff = ((partials.mode_B2freq(bin_f0, x + 1, B / 4.0)) / x / bin_f0) ideal_above_above = ( (partials.mode_B2freq(bin_f0, x + 2, 0) - above_bins) / x / bin_f0) ideal_ns = numpy.array([h.n for h in idealss]) ideal_ys = [h.fft_bin / h.n for h in idealss] ideal_ns_next = ideal_ns - 1 ideal_ys_next = [h.fft_bin / (h.n - 1) for h in idealss] ysa = numpy.array(ys) pylab.figure() pylab.plot(ns, ysa, '.') numpy.savetxt( "ns_ys.txt", numpy.vstack( (numpy.array(ns), stft.bin2hertz(numpy.array(ysa), sample_rate))).transpose()) pylab.plot(ideal_ns, ideal_ys, '.', color="green") pylab.plot(ideal_ns_next, ideal_ys_next, '.', color="green") pylab.plot(x, predicted, '-') numpy.savetxt( "ns_predicted.txt", numpy.vstack( (numpy.array(x), stft.bin2hertz(numpy.array(predicted), sample_rate))).transpose()) pylab.plot(x, ideal_below, '-', color="orange") pylab.plot(x, ideal_above_safe, '-', color="pink") pylab.plot(x, ideal_above, '-', color="orange") #pylab.plot(x, ideal_above_above, '-', color="orange") #pylab.plot(x, ideal_above_semi_stiff, '-', color="orange") pylab.plot(omit_ns, omit_ys, 'rx') numpy.savetxt( "omit_ns_ys.txt", numpy.vstack((numpy.array(omit_ns), stft.bin2hertz(numpy.array(omit_ys), sample_rate))).transpose()) #pylab.plot(xs, weights, 'o') pylab.xlim(0) pylab.ylim([0.99 * min(ys), 1.01 * max(ys)])
def peval(x, p): #if False: if True: if any(p < 0): return numpy.zeros(len(x)) fn = partials.mode_B2freq(f0, x, B) wn = 2*numpy.pi*fn nf = p[0] na = p[1] nb = p[2] ns = ((T * (nf + na/wn) + B*nb*(x*numpy.pi/L)**2) / (T + B*(x*numpy.pi/L)**2)) return ns #return 1.0 / (p[0] + p[1]*(x-1)**p[2]) #return (p[0] + p[1]*(x-1)**2) #return (p[0] + p[1]*(x-1)**2) #return (hardcode_first + p[2]*((x-1)**1)) return (hardcode_first + p[1]*((x-1)**2))
def plot_ideal_lines(bin_f0, num_harmonics, sample_rate): ideal_freqs = numpy.array( [stft.bin2hertz( partials.mode_B2freq( bin_f0, i+1, 0), sample_rate) for i in xrange(num_harmonics) ] ) for i, line in enumerate(ideal_freqs): if i == 0: pylab.axvline( line, color="pink", #linewidth=3.0, alpha=0.8, label="ideal", ) else: pylab.axvline( line, color="pink", #linewidth=3.0, alpha=0.8, #label="ideal", )
def plot_ideal_lines(bin_f0, num_harmonics, sample_rate): ideal_freqs = numpy.array([ stft.bin2hertz(partials.mode_B2freq(bin_f0, i + 1, 0), sample_rate) for i in xrange(num_harmonics) ]) for i, line in enumerate(ideal_freqs): if i == 0: pylab.axvline( line, color="pink", #linewidth=3.0, alpha=0.8, label="ideal", ) else: pylab.axvline( line, color="pink", #linewidth=3.0, alpha=0.8, #label="ideal", )
def residuals(p, y, x): return (y - (partials.mode_B2freq(p[0], x, abs(p[1])) / x))
def write_plot(base_filename): filenames = glob.glob(os.path.join(base_filename, "spectrum-*.txt")) basename = base_filename.split('/')[-2] wav_filename = os.path.split(os.path.dirname(base_filename))[-1] base_freq = expected_frequencies.get_freq_from_filename(wav_filename) filenames.sort() Bs = numpy.loadtxt(os.path.join(base_filename, 'Bs.txt')) SAMPLE_RATE, base_freq, B, limit, below, above = Bs limit = int(limit) num_harms = None for i, filename in enumerate(filenames): seconds = i * HOPSIZE / float(SAMPLE_RATE) if seconds > MAX_SECONDS: print "Reached time cutoff of %.1f" % MAX_SECONDS return print i, filename fft = numpy.loadtxt(filename) harms = numpy.loadtxt(filename.replace("spectrum-", "harms-")) #noise = numpy.loadtxt(os.path.join( # base_filename, "noise-floor.txt")) outfilename = filename.replace("spectrum-", "").replace(".txt", ".png") freqs_estimate_int = [i * base_freq for i in range(1, limit + 1)] freqs_estimate_B = [ partials.mode_B2freq(base_freq, i, B) for i in range(1, limit + 1) ] # DEBUG for g string only for j, freq in enumerate(freqs_estimate_int): if j == 0: pylab.axvline(freq, color="y", label="ideal freq.") else: pylab.axvline(freq, color="y") for j, freq in enumerate(freqs_estimate_B): low = stft.bin2hertz( stft.hertz2bin(freq, SAMPLE_RATE) - below, SAMPLE_RATE) high = stft.bin2hertz( stft.hertz2bin(freq, SAMPLE_RATE) + above, SAMPLE_RATE) if j == 0: pylab.axvspan(low, high, color="c", alpha=0.3, label="search range") else: pylab.axvspan(low, high, color="c", alpha=0.3) pylab.plot(fft[:, 0], fft[:, 1]) pylab.plot(harms[:, 0], harms[:, 1], 'ro', label="peaks") #pylab.semilogy(noise[:,0], noise[:,1], 'g-') if num_harms is None: num_harms = len(harms[:, 0]) #pylab.xlim([0, (num_harms+3)*base_freq]) if max_freq > 0: pylab.xlim([min_freq, max_freq]) pylab.ylim([AXIS_Y_BOTTOM, AXIS_Y_TOP]) pylab.xlabel("Frequency [Hz]") pylab.ylabel("Amplitude [dB]") pylab.title("Evolution of harmonics: %s\n%.3fs seconds" % (basename, seconds)) #pylab.legend(bbox_to_anchor=(1.05, 1), loc=2) pylab.legend() pylab.savefig(outfilename) pylab.close()
def main(): ### init comedi = comedi_interface.Comedi() comedi.send_all(0) #comedi.send(comedi_interface.CHANNEL_A0, 1) audio = alsa_interface.Audio() audio_output_lock = multiprocessing.Lock() audio_output_lock.acquire() global logfile logfile = open(LOGFILE, 'w') # Later on, we'll say (in stimulate(), actually): # audio_output_lock.release() # sleep(some time) # pluck_data = wait_left(... # and this should play the whole precomputed output block # starting the input some time into it. freq_queue, audio_in_queue = audio.begin(audio_output_lock) alsa_stream_in = audio.alsa_stream_in ### get silence if False: global silence print "getting silence..." silence = stimulate(0.0, 1*SECONDS_MEASUREMENT, freq_queue, audio_output_lock, audio_in_queue, comedi, alsa_stream_in) print "... silence gotten" wavname = "silence.wav" if FORMAT_NUMPY == numpy.int16: scipy.io.wavfile.write(wavname, INPUT_RATE, silence) else: scipy.io.wavfile.write(wavname, INPUT_RATE, numpy.int32((2**31-1)*silence)) #f0=438.0 # Expected frequency of fundamental #f0=658.0 # Expected frequency of fundamental #f0=2*658.0 #f0= .0 # Expected frequency of fundamental #f0 = 143.0 f0 = 220.0 B = 0.0 tries = LOCATE_F0_ATTEMPTS max_partials = MAX_PARTIAL series = [0] * (max_partials+1) start_partial = 1 tested_modes = [] tested_favgs = [] ### kick-start process #start_partial = 10 #tested_modes = [1, 2, 3, 4, 5, 6, 7, 8, 9] #tested_favgs = [ 439.69665405 , 879.34497282 ,1321.67762859, 1763.11055972 , 2204.01194094 , # 2649.08665505 , 3094.1608183 , 3533.91024435 , 3986.87554256] for p in range(start_partial, max_partials+1): text = "--- mode %i" % (p) logfile.write(text+"\n") logfile.flush() outfile = open("estimates-%i.txt" % p, "w") f0, B, rsquared = estimate_f0_B.estimate_B( tested_modes, tested_favgs, f0, B) f_test = partials.mode_B2freq(f0, p, B) f_avg = 0 for attempt in range(tries): f_measured = find_peak(f_test, freq_queue, audio_output_lock, audio_in_queue, comedi, attempt, alsa_stream_in) f_avg += f_measured f_test = 0.1*f_test + 0.9*f_measured outfile.write("%f\n" % f_measured) #time.sleep(10) f_avg /= tries # no, not useful tested_modes.append(p) tested_favgs.append(f_avg) if p == 1: f0 = f_test f0, B, rsquared = estimate_f0_B.estimate_B( tested_modes, tested_favgs, f0, B) #text = "Estimated string f0: %.2f\tinharmonicity B: %.3g\tR^2 \"variability\": %.3g" % (f0, B, rsquared) text = "Estimated string f0: %.2f\tinharmonicity B: %.3g\tR^2: %.3g" % (f0, B, rsquared) logfile.write(text+"\n") logfile.flush() #f0 = f0avg * (p + 1) / p series[p] = f_avg outfile.close() series = series[1:] # High pass de-glitch filter # dgfa, dgfb = sig.iirdesign(50.*0.5/INPUT_RATE, 20*0.5/INPUT_RATE, 3, 70) # (but we still save the raw data) numpy.savetxt( os.path.join(SAVE_PATH, "detected-freqs.txt"), numpy.array(series) ) exit(1) for f0_idx in range(len(series)) : f0 = series[f0_idx] for attempt in range(MEASUREMENTS) : pluck = stimulate(f0, SECONDS_MEASUREMENT, freq_queue, audio_output_lock, audio_in_queue, comedi, alsa_stream_in) save_pluck_data(f0_idx+1, attempt, pluck) if PLOT_TRIAL: fnb = plot_file_name(f0_idx+1, attempt) graphname = fnb + "-measured.png" pluckplt = BackgroundPlot(7, graphname, range(len(pluck)), pluck, title=fnb) pluckplt.waitForPlot() os.chmod(graphname, 0666) ### clean up audio.end() audio.close() logfile.close()
def residuals_weighted(p, y, x): return ((y - (partials.mode_B2freq(p[0], x, abs(p[1])) / x))) * weights
def generate_data(self, dirname, basename, plot_harms=False): #png_dirname = os.path.join(dirname, 'png') #if not os.path.exists(png_dirname): # os.makedirs(png_dirname) if defs.ONLY_FILES_CONTAINING: search_filename = '%s*%s*wav' % ( basename, defs.ONLY_FILES_CONTAINING) else: search_filename = basename + '*.wav' filenames = glob.glob( os.path.join(dirname, search_filename)) filenames = filter(lambda x: "noise" not in x, filenames) filenames.sort() if defs.ONLY_N_FILES > 0: filenames = filenames[:defs.ONLY_N_FILES] _, _, _, final = estimate_f0_B.estimate_f0_B(filenames) f0 = final.f0 B = final.B limit = final.highest_mode stats = HarmonicsStats() stats.num_files = len(filenames) decays = [] for wav_filename_count, wav_filename in enumerate(filenames): basename = os.path.basename(wav_filename) #print "Processing", wav_filename pickle_filename = wav_filename+".stft.pickle" if os.path.exists(pickle_filename): pickle_file = open(pickle_filename, 'rb') harmonics, hop_rate = pickle.load(pickle_file) pickle_file.close() #print "... read pickle" else: #print "... calculating new" #frequency = expected_frequencies.get_freq_from_filename( # wav_filename, f0, B) harmonics, hop_rate = stft_interface.get_harmonics( wav_filename, f0, B, limit) pickle_file = open(pickle_filename, 'wb') pickle.dump( (harmonics, hop_rate), pickle_file, -1) pickle_file.close() #print "... wrote pickle" nums = tables.save_partials(os.path.splitext(basename)[0]) if nums: dest_dir = "out/" for num in nums: h = harmonics[num] #print h.n data = numpy.vstack( ( h.frame_numbers*hop_rate, stft.amplitude2db(h.mags) )).transpose() filename = dest_dir + '/partials-%s-%i.txt' % ( basename, num) numpy.savetxt( filename, data) print "Wrote to %s" % filename for i, h in enumerate(harmonics): stats.num_harms_original += 1 if len(h.mags) < 2: stats.num_harms_max_no_above_noise += 1 continue #if h.n > 0: # pylab.figure() # pylab.semilogy(h.mags, '.') # pylab.title("mode %i" % h.n) # pylab.show() #N = 16 #b, a = scipy.signal.butter(N, 0.25) #b = scipy.signal.firwin(N, 0.25) #a = 1.0 #zi = scipy.signal.lfiltic(b, a, h.mags[0:N], # h.mags[0:N]) #h.mags, zf = scipy.signal.lfilter(b, a, h.mags, # zi=zi) #pylab.semilogy(h.mags) #pylab.show() #if defs.HARMONICS_PRINT_SUMMARY: # print "n: %i\tbegin" %(h.n) noise_mean = get_noise_mean(h.mags, 0.9) #noise_top = get_noise_top(h.mags, 0.9) #frames_above = num_above_noise(h.mags, noise_top) frames_above = num_above_noise(h.mags, noise_mean) #print h.n, "above:", frames_above noise_top_extra_min = stft.db2amplitude( stft.amplitude2db(noise_mean) + defs.HARMONIC_MAX_DB_ABOVE_NOISE_TOP) if max(h.mags) < noise_top_extra_min: # print "bail noise_top_extra" # # FIXME: special stats.num_harms_max_no_above_noise += 1 continue #print h.n, frames_above if frames_above < defs.HARMONIC_MIN_HOPS_ABOVE_NOISE: stats.num_harms_num_no_above_noise += 1 #print "not enough above noise top", frames_above continue ### experiment: only take beginning #h.frame_numbers = h.frame_numbers[:frames_above] #h.mags = h.mags[:frames_above] ### experiment: test the derivative #dh_mags = numpy.zeros(len(h.mags)-1) #for i in range(0, len(h.mags)-1): # subtraction on log scale #dh_mags[i] = (h.mags[i+1] / h.mags[i]) * ( # 1.0 + h.mags[i]) # dh_mags[i] = (h.mags[i+1] - h.mags[i]) #ddh_mags = numpy.zeros(len(dh_mags)) #for i in range(0, len(dh_mags)-1): # ddh_mags[i] = dh_mags[i+1] - dh_mags[i] #dh_mags = (h.mags[1:] - h.mags[:-1]) #sub = (dh_mags > 0) ##print dh_mags * sub #num_below_zero = (dh_mags * sub).sum() #print "bad: %.3g" % (float(num_below_zero) / len(dh_mags) ) ##pylab.plot(dh_mags) ##pylab.show() #print "%.3g\t%.3g\t%.3g\t%.3g" % ( # scipy.std(dh_mags), scipy.median(dh_mags), # scipy.std(ddh_mags), scipy.median(ddh_mags)) #if h.n in defs.HARMONICS_FIT_PLOT_N: #if False: # #pylab.plot(h.mags, '-o') # pylab.plot(dh_mags, '-') # pylab.plot(ddh_mags, '-*') # #pylab.xlim([0, 30]) # # pylab.show() #exit(1) #num_harms_above_noise += 1 ts = hop_rate * h.frame_numbers if h.n == defs.HARMONICS_FIT_PLOT_N: show=True plot=False plot_last=True else: show=False plot=False plot_last=defs.HARMONICS_FIT_PLOT fit, rsquared, variance = decay_exponential.fit_best_exponential( ts, h.mags, noise_mean=noise_mean, show=show, plot=plot, plot_last=plot_last) if fit is None: stats.num_harms_no_fit += 1 print "bail from no fit" continue #alpha = fit[2] alpha = fit[1] #drop_amplitude = fit[0] / noise_mean drop_amplitude = max(h.mags) / noise_mean drop_db = stft.amplitude2db(drop_amplitude) #print drop_db #if drop_db < defs.HARMONIC_MIN_DROP_DB: # stats.num_harms_no_drop += 1 # continue if rsquared < defs.HARMONIC_FIT_MIN_RSQUARED: stats.num_harms_no_rsquared += 1 continue #if variance > defs.HARMONIC_FIT_MAX_VARIANCE: # stats.num_harms_no_variance += 1 # continue #if variance > 1.0: # continue freq = partials.mode_B2freq(f0, h.n, B) w = 2*numpy.pi*freq Q = w / (2*alpha) decay = classes.Decay(freq, w, h.n, alpha, Q, rsquared, variance, drop_db) decays.append(decay) stats.num_harms_end += 1 if defs.HARMONICS_PRINT_SUMMARY: print "n: %i\t%.1f\tdecay: %.2f\tr-squared: %.2f\tvariance: %.2f\tdrop: %.2f db" % ( h.n, freq, alpha, rsquared, variance, drop_db) #print "%s\t%i\t%i\t%i\t%i\t%i" % ( #print "%s\t%i | \t%i\t%i\t%i\t| %i" % ( # basename, # num_harms_original, # num_harms_no_above_noise, # num_harms_no_fit, # #num_harms_no_rsquared, # num_harms_no_drop, # num_harms_end, # ) print "dropped:", stats.num_harms_max_no_above_noise, stats.num_harms_num_no_above_noise, def dot_color(d): #rs = 1.0/d.variance #if rs > 10.: # rs = 10. #rs = 10*d.rsquared rs = d.drop/10.0 rss = rs/10.0 dot = '.' markersize = 5 + 5.0*(rss) color = matplotlib.cm.winter(1.-rss) return dot, color, markersize if defs.HARMONICS_PLOT_DECAYS or plot_harms: pylab.figure() for d in decays: #dot, color, markersize = dot_color(d.rsquared) dot, color, markersize = dot_color(d) pylab.plot(d.n, d.alpha, dot, color=color, markersize=markersize, linewidth=0, ) pylab.xlabel("mode") pylab.ylabel("decay rates") pylab.xlim([0, max([d.n for d in decays])+1]) #pylab.legend() if defs.HARMONICS_PLOT_Q: pylab.figure() #print "# n, loss factor, weight" for d in decays: #print "%i, %.2e, %.2e" %(d.n, 1./d.Q, d.rsquared) #dot, color, markersize = dot_color(1.0/d.variance) dot, color, markersize = dot_color(d) #if d.variance > 10 or d.rsquared < 0.25: #if d.rsquared < 0.3: # dot = 'x' # color = 'red' #else: # print d.variance pylab.plot(d.n, d.Q, dot, color=color, markersize=markersize, linewidth=0, ) pylab.xlabel("mode") pylab.ylabel("Q") pylab.xlim([0, max([d.n for d in decays])+1]) #pylab.legend() if defs.HARMONICS_PLOT_LOSS: pylab.figure() #print "# n, loss factor, weight" for d in decays: #print "%i, %.2e, %.2e" %(d.n, 1./d.Q, d.rsquared) #dot, color, markersize = dot_color(1.0/d.variance) dot, color, markersize = dot_color(d) #if d.variance > 10 or d.rsquared < 0.25: #if d.rsquared < 0.3: # dot = 'x' # color = 'red' #else: # print d.variance pylab.plot(d.n, 1.0/d.Q, dot, color=color, markersize=markersize, linewidth=0, ) pylab.xlabel("mode") pylab.ylabel("loss") pylab.xlim([0, max([d.n for d in decays])+1]) #pylab.legend() ns = [ h.n for h in decays ] stats.highest_harm = max(ns) if (defs.HARMONICS_PLOT_DECAYS or defs.HARMONICS_PLOT_Q or defs.HARMONICS_PLOT_LOSS or plot_harms): pylab.show() return decays, f0, B, stats
def residuals_weighted(p, y, x): return ((y - (partials.mode_B2freq(p[0], x, abs(p[1])) / x) ))*weights
def estimate_f0_B(filenames): ### ASSUME: all filenames are of the same instrument-string wav_filename = filenames[0] basename = '-'.join(os.path.basename(wav_filename).split('-')[0:3]) if basename.startswith("test-440f"): return 440.0, 0, 1, 1, 1, 1 ### get initial f0 estimate base_frequency_estimate = expected_frequencies.get_freq_from_filename( wav_filename) ### get noise initial_noise_floor, initial_noise_freqs, _, _, _ = calc_noise.get_noise( wav_filename) noise_cutoff = stft.db2amplitude( stft.amplitude2db(initial_noise_floor) + defs.B_MINIMUM_HARMONIC_SNR) #### get FFT frames from audio files sample_rate = None freqs = None estimate_B_buffers_list = [] for wav_i, wav_filename in enumerate(filenames): #print wav_filename #window_buffer, sample_rate = stft.get_long_buffer_from_file(wav_filename, window_buffers, sample_rate = stft.get_buffers_from_file( wav_filename, (defs.B_NUM_BUFFERS_ESTIMATE)) if freqs is None: freqs = [ stft.bin2hertz(i, sample_rate) for i in range(stft.WINDOWSIZE / 2 + 1) ] estimate_B_buffers_this_list = [] #fft_amplitude = stft.fft_amplitude(window_buffer, sample_rate) #estimate_B_buffers_this_list.append(fft_amplitude) for window_number in range(defs.B_NUM_BUFFERS_ESTIMATE): window_buffer = window_buffers[window_number] fft_amplitude = stft.stft_amplitude(window_buffer) estimate_B_buffers_this_list.append(fft_amplitude) estimate_B_buffers_list.extend(estimate_B_buffers_this_list) estimate_B_buffers = numpy.array(estimate_B_buffers_list) ### radius of search area for peaks # used with STFT only bin_initial_estimate = stft.hertz2bin(base_frequency_estimate, sample_rate) #bin_initial_estimate = (base_frequency_estimate # * fft_amplitude.shape[0] / (sample_rate/2) # ) #print bin_initial_estimate bin_spread_below = int( math.ceil( abs( stft.hertz2bin((1.0 - defs.B_PEAK_SPREAD_BELOW_HERTZ) * base_frequency_estimate, sample_rate) - bin_initial_estimate))) bin_spread_above = int( math.ceil( stft.hertz2bin((1.0 + defs.B_PEAK_SPREAD_ABOVE_HERTZ) * base_frequency_estimate, sample_rate) - bin_initial_estimate)) #bin_spread_below = int(round(bin_initial_estimate * # defs.B_PEAK_SPREAD_BELOW_HERTZ)) #bin_spread_above = int(round(bin_initial_estimate * # defs.B_PEAK_SPREAD_BELOW_HERTZ)) #bin_spread_below_main = int( # stft.hertz2bin(defs.STFT_PEAK_SPREAD_BELOW_HERTZ*base_frequency_estimate, # sample_rate)) #bin_spread_above_main = int( # stft.hertz2bin(defs.STFT_PEAK_SPREAD_ABOVE_HERTZ*base_frequency_estimate, # sample_rate)) ### actual estimate bin_f0, B, rsquared, harmonics, limit = get_bin_f0_B( bin_initial_estimate, estimate_B_buffers, noise_cutoff, #estimate_B_buffers, numpy.zeros(defs.LONG_WINDOWSIZE+1), bin_spread_below, bin_spread_above, sample_rate) highest_harmonic = 0 for h in harmonics: if highest_harmonic < h.n: highest_harmonic = h.n limit = min(limit, highest_harmonic) # HACK: remove limit #limit = defs.TOTAL_HARMONICS #print "limit to:", limit #harmonics_enable = [True]*defs.TOTAL_HARMONICS harmonics_enable = [True] * limit bins_estimate = [ partials.mode_B2freq(bin_f0, i, B) for i in range(1, len(harmonics_enable) + 1) ] bins_naive = [i * bin_f0 for i in range(1, len(harmonics_enable) + 1)] if defs.B_PLOT: pylab.figure() pylab.plot(initial_noise_freqs, stft.amplitude2db(initial_noise_floor), color='black') #pylab.plot(initial_noise_freqs, # stft.amplitude2db(initial_noise_floor)+defs.B_MINIMUM_HARMONIC_SNR, # color='black') pylab.xlabel("Frequency (seconds)") pylab.ylabel("Power (/ dB)") for i in range(estimate_B_buffers.shape[0]): #color = matplotlib.cm.spring(float(wav_i)/len(filenames)) #color = matplotlib.cm.RdYlGn( #color = matplotlib.cm.spring( # float(i)/len(estimate_B_buffers_this_list)) pylab.plot( freqs, stft.amplitude2db(estimate_B_buffers[i, :]), #color=color, color="orange", alpha=0.5, label=basename, ) for est in bins_estimate: low = stft.bin2hertz(est - bin_spread_below, sample_rate) high = stft.bin2hertz(est + bin_spread_above, sample_rate) if True: pylab.axvspan(low, high, color='c', alpha=0.3) else: pylab.axvline( stft.bin2hertz(est, sample_rate), color='cyan', alpha=0.3, #linewidth=2.0 ) for naive in bins_naive: freq = stft.bin2hertz(naive, sample_rate) pylab.axvline( freq, color='grey', alpha=0.2, #linewidth=2.0 ) for j, harm in enumerate(harmonics): if harm.mag == 0: continue fn = stft.bin2hertz(harm.fft_bin, sample_rate) mag = stft.amplitude2db(harm.mag) #pylab.plot(fn, mag, 'o', # color='green' # ) pylab.xlabel("Frequency") pylab.ylabel("Decibels") if defs.B_DUMP_HARMS: t_fns = [] t_mags = [] for j, harm in enumerate(harmonics): if harm.mag == 0: continue fn = stft.bin2hertz(harm.fft_bin, sample_rate) mag = stft.amplitude2db(harm.mag) t_fns.append(fn) t_mags.append(mag) data = numpy.vstack((t_fns, t_mags)).transpose() numpy.savetxt("B-harms.txt", data) if defs.B_PLOT: pylab.show() f0 = stft.bin2hertz(bin_f0, sample_rate) stiff_ideal_limit = stiff_ideal_conflict.find_limit( bin_f0, B, bin_spread_below, bin_spread_above) lim = min(stiff_ideal_limit, limit) detected_freqs = StringFreqsB(f0, B, lim) stats = StringFreqsB_stats() stats.num_files = len(filenames) stats.rsquared = rsquared stats.highest_mode_detected = limit stats.highest_mode_stiff_ideal = stiff_ideal_limit stats.basename = basename adjusted_B, delta_fn = adjust_B.adjust(basename, limit, f0, B) if adjusted_B is not None: stiff_ideal_lim_adjusted = stiff_ideal_conflict.find_limit( bin_f0, adjusted_B, bin_spread_below, bin_spread_above) lim = min(stiff_ideal_lim_adjusted, limit) adjusted_freqs = StringFreqsB(f0, adjusted_B, lim) adjusted_freqs.delta_fn = delta_fn stats.highest_mode_stiff_ideal_adjusted = stiff_ideal_lim_adjusted stats.delta_fn = delta_fn final = StringFreqsB( f0, adjusted_B, min(stats.highest_mode_detected, stats.highest_mode_stiff_ideal, stiff_ideal_lim_adjusted)) else: adjusted_freqs = None final = StringFreqsB( f0, B, min(stats.highest_mode_detected, stats.highest_mode_stiff_ideal)) return detected_freqs, adjusted_freqs, stats, final
def write_plot(base_filename): filenames = glob.glob(os.path.join( base_filename, "spectrum-*.txt")) basename = base_filename.split('/')[-2] wav_filename = os.path.split( os.path.dirname(base_filename) )[-1] base_freq = expected_frequencies.get_freq_from_filename(wav_filename) filenames.sort() Bs = numpy.loadtxt(os.path.join(base_filename, 'Bs.txt')) SAMPLE_RATE, base_freq, B, limit, below, above = Bs limit = int(limit) num_harms = None for i, filename in enumerate(filenames): seconds = i*HOPSIZE / float(SAMPLE_RATE) if seconds > MAX_SECONDS: print "Reached time cutoff of %.1f" % MAX_SECONDS return print i, filename fft = numpy.loadtxt(filename) harms = numpy.loadtxt(filename.replace("spectrum-", "harms-")) #noise = numpy.loadtxt(os.path.join( # base_filename, "noise-floor.txt")) outfilename = filename.replace("spectrum-","").replace(".txt", ".png") freqs_estimate_int = [ i*base_freq for i in range(1,limit+1)] freqs_estimate_B = [ partials.mode_B2freq(base_freq, i, B) for i in range(1,limit+1)] # DEBUG for g string only for j, freq in enumerate(freqs_estimate_int): if j == 0: pylab.axvline(freq, color="y", label="ideal freq.") else: pylab.axvline(freq, color="y") for j, freq in enumerate(freqs_estimate_B): low = stft.bin2hertz( stft.hertz2bin(freq, SAMPLE_RATE) - below, SAMPLE_RATE) high = stft.bin2hertz( stft.hertz2bin(freq, SAMPLE_RATE) + above, SAMPLE_RATE) if j == 0: pylab.axvspan(low, high, color="c", alpha=0.3, label="search range") else: pylab.axvspan(low, high, color="c", alpha=0.3) pylab.plot(fft[:,0], fft[:,1]) pylab.plot(harms[:,0], harms[:,1], 'ro', label="peaks") #pylab.semilogy(noise[:,0], noise[:,1], 'g-') if num_harms is None: num_harms = len(harms[:,0]) #pylab.xlim([0, (num_harms+3)*base_freq]) if max_freq > 0: pylab.xlim([min_freq, max_freq]) pylab.ylim([AXIS_Y_BOTTOM, AXIS_Y_TOP]) pylab.xlabel("Frequency [Hz]") pylab.ylabel("Amplitude [dB]") pylab.title("Evolution of harmonics: %s\n%.3fs seconds" % ( basename, seconds)) #pylab.legend(bbox_to_anchor=(1.05, 1), loc=2) pylab.legend() pylab.savefig(outfilename) pylab.close()
def main(): ### init comedi = comedi_interface.Comedi() comedi.send_all(0) #comedi.send(comedi_interface.CHANNEL_A0, 1) audio = alsa_interface.Audio() audio_input_lock = multiprocessing.Lock() audio_output_lock = multiprocessing.Lock() audio_input_lock.acquire() audio_output_lock.acquire() # Later on, we'll say: # audio_output_lock.release() # sleep(some time) # pluck_data = wait_left(6.0) # ## audio_input_lock.release() # # get some data # # When everything settles down, both processes should # # release their locks (might need some extra logic in them) # audio_input_lock.acquire() # audio_output_lock.acquire() # queue.send(next buffer of stuff) # as many times as is necessary, # and this should play the whole precomputed output block # starting the input some time into it. # Seems the separate output thread tascam_input_process # is deprecated in alsa_interface.py, so need some consultancy # on whether this is what you're thinking about. # Also need to precompute the blocks instead of using the # freq_queue stuff which might be a bit of a big change. freq_queue, audio_in_queue = audio.begin(audio_input_lock) alsa_stream_in = audio.alsa_stream_in f0=438.0 # Expected frequency of fundamental B = 0.0 tries = LOCATE_F0_ATTEMPTS max_partials = MAX_PARTIAL series = [0] * (max_partials+1) tested_modes = [] tested_favgs = [] for p in range(1, max_partials+1): outfile = open("estimates-%i.txt" % p, "w") f_test = partials.mode_B2freq(f0, p, B) f_avg = 0 for attempt in range(tries): f_measured = find_peak(f_test, freq_queue, audio_in_queue, comedi, attempt, alsa_stream_in) f_avg += f_measured f_test = 0.1*f_test + 0.9*f_measured outfile.write("%f\n" % f_measured) #time.sleep(10) f_avg /= tries tested_modes.append(p) tested_favgs.append(f_avg) f0, B, rsquared = partials.estimate_B( tested_modes, tested_favgs, f0, B) print "--------------" print "%.2f\t%.3g\t%.3g" % (f0, B, rsquared) print "--------------" #f0 = f0avg * (p + 1) / p series[p] = f_avg outfile.close() series = series[1:] # High pass de-glitch filter dgfa, dgfb = sig.iirdesign(50.*0.5/INPUT_RATE, 20*0.5/INPUT_RATE, 3, 70) numpy.savetxt( os.path.join(SAVE_PATH, "detected-freqs.txt"), numpy.array(series) ) for f0_idx in range(len(series)) : f0 = series[f0_idx] for attempt in range(MEASUREMENTS) : pluck = stimulate(f0, SECONDS_MEASUREMENT, freq_queue, audio_in_queue, comedi, alsa_stream_in) save_pluck_data(f0_idx+1, attempt, pluck) if PLOT_TRIAL: fnb = plot_file_name(f0_idx+1, attempt) graphname = fnb + "-measured.png" pluckplt = BackgroundPlot(10, graphname, range(len(pluck)), pluck, title=fnb) pluckplt.waitForPlot() os.chmod(graphname, 0666) else: time.sleep(10) ### clean up audio.end() audio.close()
def estimate_f0_B(filenames): ### ASSUME: all filenames are of the same instrument-string wav_filename = filenames[0] basename='-'.join(os.path.basename(wav_filename).split('-')[0:3]) if basename.startswith("test-440f"): return 440.0, 0, 1, 1, 1, 1 ### get initial f0 estimate base_frequency_estimate = expected_frequencies.get_freq_from_filename( wav_filename) ### get noise initial_noise_floor, initial_noise_freqs, _, _, _ = calc_noise.get_noise(wav_filename) noise_cutoff = stft.db2amplitude( stft.amplitude2db(initial_noise_floor)+defs.B_MINIMUM_HARMONIC_SNR) #### get FFT frames from audio files sample_rate = None freqs = None estimate_B_buffers_list = [] for wav_i, wav_filename in enumerate(filenames): #print wav_filename #window_buffer, sample_rate = stft.get_long_buffer_from_file(wav_filename, window_buffers, sample_rate = stft.get_buffers_from_file(wav_filename, (defs.B_NUM_BUFFERS_ESTIMATE)) if freqs is None: freqs = [ stft.bin2hertz(i, sample_rate) for i in range(stft.WINDOWSIZE/2+1) ] estimate_B_buffers_this_list = [] #fft_amplitude = stft.fft_amplitude(window_buffer, sample_rate) #estimate_B_buffers_this_list.append(fft_amplitude) for window_number in range(defs.B_NUM_BUFFERS_ESTIMATE): window_buffer = window_buffers[window_number] fft_amplitude = stft.stft_amplitude(window_buffer) estimate_B_buffers_this_list.append(fft_amplitude) estimate_B_buffers_list.extend(estimate_B_buffers_this_list) estimate_B_buffers = numpy.array(estimate_B_buffers_list) ### radius of search area for peaks # used with STFT only bin_initial_estimate = stft.hertz2bin(base_frequency_estimate, sample_rate) #bin_initial_estimate = (base_frequency_estimate # * fft_amplitude.shape[0] / (sample_rate/2) # ) #print bin_initial_estimate bin_spread_below = int(math.ceil(abs( stft.hertz2bin( (1.0-defs.B_PEAK_SPREAD_BELOW_HERTZ)*base_frequency_estimate, sample_rate) - bin_initial_estimate))) bin_spread_above = int(math.ceil( stft.hertz2bin( (1.0+defs.B_PEAK_SPREAD_ABOVE_HERTZ)*base_frequency_estimate, sample_rate) - bin_initial_estimate)) #bin_spread_below = int(round(bin_initial_estimate * # defs.B_PEAK_SPREAD_BELOW_HERTZ)) #bin_spread_above = int(round(bin_initial_estimate * # defs.B_PEAK_SPREAD_BELOW_HERTZ)) #bin_spread_below_main = int( # stft.hertz2bin(defs.STFT_PEAK_SPREAD_BELOW_HERTZ*base_frequency_estimate, # sample_rate)) #bin_spread_above_main = int( # stft.hertz2bin(defs.STFT_PEAK_SPREAD_ABOVE_HERTZ*base_frequency_estimate, # sample_rate)) ### actual estimate bin_f0, B, rsquared, harmonics, limit = get_bin_f0_B( bin_initial_estimate, estimate_B_buffers, noise_cutoff, #estimate_B_buffers, numpy.zeros(defs.LONG_WINDOWSIZE+1), bin_spread_below, bin_spread_above, sample_rate) highest_harmonic = 0 for h in harmonics: if highest_harmonic < h.n: highest_harmonic = h.n limit = min(limit, highest_harmonic) # HACK: remove limit #limit = defs.TOTAL_HARMONICS #print "limit to:", limit #harmonics_enable = [True]*defs.TOTAL_HARMONICS harmonics_enable = [True]*limit bins_estimate = [ partials.mode_B2freq(bin_f0, i, B) for i in range(1,len(harmonics_enable)+1) ] bins_naive = [ i*bin_f0 for i in range(1,len(harmonics_enable)+1) ] if defs.B_PLOT: pylab.figure() pylab.plot(initial_noise_freqs, stft.amplitude2db(initial_noise_floor), color='black') #pylab.plot(initial_noise_freqs, # stft.amplitude2db(initial_noise_floor)+defs.B_MINIMUM_HARMONIC_SNR, # color='black') pylab.xlabel("Frequency (seconds)") pylab.ylabel("Power (/ dB)") for i in range(estimate_B_buffers.shape[0]): #color = matplotlib.cm.spring(float(wav_i)/len(filenames)) #color = matplotlib.cm.RdYlGn( #color = matplotlib.cm.spring( # float(i)/len(estimate_B_buffers_this_list)) pylab.plot(freqs, stft.amplitude2db(estimate_B_buffers[i,:]), #color=color, color="orange", alpha=0.5, label=basename, ) for est in bins_estimate: low = stft.bin2hertz(est - bin_spread_below, sample_rate) high = stft.bin2hertz(est + bin_spread_above, sample_rate) if True: pylab.axvspan(low, high, color='c', alpha=0.3) else: pylab.axvline(stft.bin2hertz(est, sample_rate), color='cyan', alpha=0.3, #linewidth=2.0 ) for naive in bins_naive: freq = stft.bin2hertz(naive, sample_rate) pylab.axvline(freq, color='grey', alpha=0.2, #linewidth=2.0 ) for j, harm in enumerate(harmonics): if harm.mag == 0: continue fn = stft.bin2hertz(harm.fft_bin, sample_rate) mag = stft.amplitude2db(harm.mag) #pylab.plot(fn, mag, 'o', # color='green' # ) pylab.xlabel("Frequency") pylab.ylabel("Decibels") if defs.B_DUMP_HARMS: t_fns = [] t_mags = [] for j, harm in enumerate(harmonics): if harm.mag == 0: continue fn = stft.bin2hertz(harm.fft_bin, sample_rate) mag = stft.amplitude2db(harm.mag) t_fns.append(fn) t_mags.append(mag) data = numpy.vstack((t_fns, t_mags)).transpose() numpy.savetxt("B-harms.txt", data) if defs.B_PLOT: pylab.show() f0 = stft.bin2hertz(bin_f0, sample_rate) stiff_ideal_limit = stiff_ideal_conflict.find_limit(bin_f0, B, bin_spread_below, bin_spread_above) lim = min(stiff_ideal_limit, limit) detected_freqs = StringFreqsB(f0, B, lim) stats = StringFreqsB_stats() stats.num_files = len(filenames) stats.rsquared = rsquared stats.highest_mode_detected = limit stats.highest_mode_stiff_ideal = stiff_ideal_limit stats.basename = basename adjusted_B, delta_fn = adjust_B.adjust(basename, limit, f0, B) if adjusted_B is not None: stiff_ideal_lim_adjusted = stiff_ideal_conflict.find_limit( bin_f0, adjusted_B, bin_spread_below, bin_spread_above) lim = min(stiff_ideal_lim_adjusted, limit) adjusted_freqs = StringFreqsB(f0, adjusted_B, lim) adjusted_freqs.delta_fn = delta_fn stats.highest_mode_stiff_ideal_adjusted = stiff_ideal_lim_adjusted stats.delta_fn = delta_fn final = StringFreqsB(f0, adjusted_B, min(stats.highest_mode_detected, stats.highest_mode_stiff_ideal, stiff_ideal_lim_adjusted)) else: adjusted_freqs = None final = StringFreqsB(f0, B, min(stats.highest_mode_detected, stats.highest_mode_stiff_ideal)) return detected_freqs, adjusted_freqs, stats, final
def residuals(p, y, x): return (y - (partials.mode_B2freq(p[0], x, abs(p[1])) / x) )
def stiff_plus(bin_f0, B, n): return partials.mode_B2freq(bin_f0, n, B)