예제 #1
0
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)])
예제 #2
0
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)])
예제 #3
0
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)
예제 #4
0
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)
예제 #5
0
def plot_stft_first_n(window_number, n_windows, fft_amplitude, sample_rate,
                      harms, wav_filename, bin_f0, B, bin_spread_below,
                      bin_spread_above):
    #if window_number % 2 == 0:
    count = window_number + 1
    color = matplotlib.cm.gnuplot(float(count) / (n_windows + 1))
    #label = "%.3f seconds" % (float(count) * stft.HOPSIZE/sample_rate)

    bin_freqs = [
        stft.bin2hertz(bin_num, sample_rate)
        for bin_num, amplitude in enumerate(fft_amplitude)
    ]
    harms_freqs = [
        stft.bin2hertz(h.fft_bin, sample_rate) for h in harms if h.mag > 0
    ]
    harms_mags = [stft.amplitude2db(h.mag) for h in harms if h.mag > 0]

    plot_ideal_lines(bin_f0, len(harms), sample_rate)
    plot_stiff_area(bin_f0, B, bin_spread_below, bin_spread_above, harms,
                    sample_rate)
    pylab.plot(
        bin_freqs,
        stft.amplitude2db(fft_amplitude),
        '-',
        color=color,
        label="fft",
    )
    pylab.plot(
        harms_freqs,
        harms_mags,
        'o',
        color=color,
        label="harmonics",
    )

    #for est in bins_estimate:
    #    low = stft.bin2hertz(est - bin_spread, sample_rate)
    #    high = stft.bin2hertz(est + bin_spread, sample_rate)
    #    pylab.axvspan(low, high, color='c', alpha=0.3)
    if window_number >= n_windows - 1:
        import calc_noise
        initial_noise_floor, initial_noise_freqs, _, _, _ = calc_noise.get_noise(
            wav_filename)
        pylab.plot(
            initial_noise_freqs,
            stft.amplitude2db(initial_noise_floor),
            label="initial noise floor",
            color="black",
        )
예제 #6
0
def plot_resynth(harmonics, fft, sample_rate):
    freqs = [ stft.bin2hertz(i, sample_rate) for i in xrange(len(fft)) ]
    synth_min_cutoff = 0.5 * min(numpy.where(fft>0, fft, 1))
    length = len(fft)
    for i, sp in enumerate(harmonics):
        synthesized_peak = partials.qifft_synthesize(sp.fft_bin,
            sp.mag, sp.curvature_a, length)
        synthesized_peak = numpy.where(
            synthesized_peak > synth_min_cutoff,
            synthesized_peak, 0)
        if i == 0:
            pylab.plot(
                [ f for f, m in zip(freqs, synthesized_peak) if m > 0.0 ],
                stft.amplitude2db(
                    numpy.array(
                    [ m for f, m in zip(freqs, synthesized_peak) if m > 0.0 ],
                    )),
                '.-', color="yellow", alpha=0.8,
                label="resynthesized peak")
        else:
            pylab.plot(
                [ f for f, m in zip(freqs, synthesized_peak) if m > 0.0 ],
                stft.amplitude2db(
                    numpy.array(
                    [ m for f, m in zip(freqs, synthesized_peak) if m > 0.0 ],
                    )),
                '.-', color="yellow", alpha=0.8)
예제 #7
0
def plot_resynth(harmonics, fft, sample_rate):
    freqs = [stft.bin2hertz(i, sample_rate) for i in xrange(len(fft))]
    synth_min_cutoff = 0.5 * min(numpy.where(fft > 0, fft, 1))
    length = len(fft)
    for i, sp in enumerate(harmonics):
        synthesized_peak = partials.qifft_synthesize(sp.fft_bin, sp.mag,
                                                     sp.curvature_a, length)
        synthesized_peak = numpy.where(synthesized_peak > synth_min_cutoff,
                                       synthesized_peak, 0)
        if i == 0:
            pylab.plot(
                [f for f, m in zip(freqs, synthesized_peak) if m > 0.0],
                stft.amplitude2db(
                    numpy.array([
                        m for f, m in zip(freqs, synthesized_peak) if m > 0.0
                    ], )),
                '.-',
                color="yellow",
                alpha=0.8,
                label="resynthesized peak")
        else:
            pylab.plot(
                [f for f, m in zip(freqs, synthesized_peak) if m > 0.0],
                stft.amplitude2db(
                    numpy.array([
                        m for f, m in zip(freqs, synthesized_peak) if m > 0.0
                    ], )),
                '.-',
                color="yellow",
                alpha=0.8)
예제 #8
0
def plot_peaks(partials, sample_rate):
    pylab.plot( [
            stft.bin2hertz(f.fft_bin, sample_rate)
            for f in partials],
        [stft.amplitude2db(f.mag) for f in partials],
        'o', color="red",
        label="detected peaks")
예제 #9
0
def plot_fft(fft, sample_rate):
    freqs = [stft.bin2hertz(i, sample_rate) for i in xrange(len(fft))]
    pylab.plot([f for f, m in zip(freqs, fft) if m > 0.0],
               [stft.amplitude2db(m) for f, m in zip(freqs, fft) if m > 0.0],
               '.-',
               alpha=0.9,
               label="fft above noise")
예제 #10
0
def plot_fft(fft, sample_rate):
    freqs = [ stft.bin2hertz(i, sample_rate) for i in xrange(len(fft)) ]
    pylab.plot(
        [ f for f, m in zip(freqs, fft) if m > 0.0 ],
        [ stft.amplitude2db(m) for f, m in zip(freqs, fft) if m > 0.0 ],
        '.-',
        alpha=0.9,
        label="fft above noise")
예제 #11
0
def plot_stft_first_n(window_number, n_windows,
                fft_amplitude, sample_rate, harms, wav_filename,
                bin_f0, B, bin_spread_below, bin_spread_above
        ):
    #if window_number % 2 == 0:
    count = window_number+1
    color = matplotlib.cm.gnuplot(float(count)/(n_windows+1))
    #label = "%.3f seconds" % (float(count) * stft.HOPSIZE/sample_rate)

    bin_freqs = [ stft.bin2hertz(bin_num, sample_rate)
        for bin_num, amplitude in enumerate(fft_amplitude) ]
    harms_freqs = [ 
        stft.bin2hertz(h.fft_bin, sample_rate)
        for h in harms if h.mag > 0]
    harms_mags = [
        stft.amplitude2db(h.mag)
        for h in harms if h.mag > 0]

    plot_ideal_lines(bin_f0, len(harms), sample_rate)
    plot_stiff_area(bin_f0, B, bin_spread_below, bin_spread_above, harms, sample_rate)
    pylab.plot(bin_freqs, stft.amplitude2db(fft_amplitude),
        '-',
        color=color,
        label="fft",
        )
    pylab.plot(harms_freqs, harms_mags, 'o',
        color=color,
        label="harmonics",
        )

    #for est in bins_estimate:
    #    low = stft.bin2hertz(est - bin_spread, sample_rate)
    #    high = stft.bin2hertz(est + bin_spread, sample_rate)
    #    pylab.axvspan(low, high, color='c', alpha=0.3)
    if window_number >= n_windows - 1:
        import calc_noise
        initial_noise_floor, initial_noise_freqs, _, _, _ = calc_noise.get_noise(
            wav_filename)
        pylab.plot(initial_noise_freqs,
            stft.amplitude2db(initial_noise_floor),
            label="initial noise floor",
            color="black",
            )
예제 #12
0
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",
                )
예제 #13
0
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",
            )
예제 #14
0
def calc_noise(wav_filename, bins=None):
    window_buffers, sample_rate = stft.get_buffers_from_file(wav_filename)

    bins = numpy.empty([
        stft.WINDOWSIZE / 2 + 1,
        len(window_buffers),
    ])
    for i, window_buffer in enumerate(window_buffers):
        fft_amplitude = stft.stft_amplitude(window_buffer)
        bins[:, i] = fft_amplitude
    print bins.shape

    freqs = [
        stft.bin2hertz(i, sample_rate) for i in range(stft.WINDOWSIZE / 2 + 1)
    ]
    #for i, window_buffer in enumerate(window_buffers):
    #    pylab.plot(freqs,
    #        stft.amplitude2db(bins[:,i]),
    #        color="blue")

    noise = numpy.empty(len(bins[:, 0]))
    means = numpy.empty(len(bins[:, 0]))
    mins = numpy.empty(len(bins[:, 0]))
    stds = numpy.empty(len(bins[:, 0]))
    for i, bin_spot in enumerate(bins):
        detected_noise = scipy.percentile(bin_spot,
                                          defs.NOISE_PERCENTILE_BELOW)
        #noise[i] = stft.db2amplitude(stft.amplitude2db(detected_noise))
        noise[i] = detected_noise
        means[i] = scipy.mean(bin_spot)
        mins[i] = bin_spot.min()
        stds[i] = scipy.std(bin_spot, ddof=1)
        #if i == 100:
        #   numpy.savetxt("noise.csv", bin_spot, delimiter=', ')

    #return noise, freqs, variance
    return noise, freqs, means, mins, stds
예제 #15
0
def calc_noise(wav_filename, bins=None):
    window_buffers, sample_rate = stft.get_buffers_from_file(wav_filename)

    bins = numpy.empty([
        stft.WINDOWSIZE/2 + 1,
        len(window_buffers),
        ])
    for i, window_buffer in enumerate(window_buffers):
        fft_amplitude = stft.stft_amplitude(window_buffer)
        bins[:,i] = fft_amplitude
    print bins.shape

    freqs = [ stft.bin2hertz(i, sample_rate)
        for i in range(stft.WINDOWSIZE/2 + 1) ]
    #for i, window_buffer in enumerate(window_buffers):
    #    pylab.plot(freqs,
    #        stft.amplitude2db(bins[:,i]),
    #        color="blue")

    noise = numpy.empty(len(bins[:,0]))
    means = numpy.empty(len(bins[:,0]))
    mins = numpy.empty(len(bins[:,0]))
    stds = numpy.empty(len(bins[:,0]))
    for i, bin_spot in enumerate(bins):
        detected_noise = scipy.percentile(bin_spot,
            defs.NOISE_PERCENTILE_BELOW)
        #noise[i] = stft.db2amplitude(stft.amplitude2db(detected_noise))
        noise[i] = detected_noise
        means[i] = scipy.mean(bin_spot)
        mins[i] = bin_spot.min()
        stds[i] = scipy.std(bin_spot, ddof=1)
        #if i == 100:
        #   numpy.savetxt("noise.csv", bin_spot, delimiter=', ')

    #return noise, freqs, variance
    return noise, freqs, means, mins, stds
예제 #16
0
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
예제 #17
0
def plot_peaks(partials, sample_rate):
    pylab.plot([stft.bin2hertz(f.fft_bin, sample_rate) for f in partials],
               [stft.amplitude2db(f.mag) for f in partials],
               'o',
               color="red",
               label="detected peaks")
예제 #18
0
def spectral_subtraction_arrays(data_array, noise_array, sample_rate):
    #data_array = data_array / float(numpy.iinfo(data_array.dtype).max)
    #noise_array = data_array / float(numpy.iinfo(noise_array.dtype).max)
    length = len(data_array)

    smallsize = int(len(noise_array) / length)
    noise_data = noise_array[:length*smallsize]
    noise_data = noise_data.reshape(smallsize, length)

    #window = scipy.signal.get_window("blackmanharris", length)
    window = scipy.signal.get_window("hamming", length)
    noise_data *= window
    noise_ffts = scipy.fftpack.fft(noise_data, axis=1)
    noise_ffts_abs = abs(noise_ffts)
    noise_power = noise_ffts_abs**2

    means_power = numpy.mean(noise_power, axis=0)

    # power to dB
    noise_db = stft.amplitude2db( numpy.sqrt(means_power[:len(means_power)/2+1])/ length )
    freqs = [stft.bin2hertz(i, sample_rate, length) for i in range(len(noise_db))]


    fft = scipy.fftpack.fft(data_array*window)
    fft_abs = abs(fft)[:len(fft)/2+1]

    fft_db = stft.amplitude2db( fft_abs / length )

    #reconstructed = fft - mins_full
    #reconstructed = fft
    #reconstructed = numpy.zeros(len(fft), dtype=complex)
    #for i in range(len(reconstructed)):
    theta = numpy.angle(fft)
    alpha = 1.0
    beta = 0.01
    r = numpy.zeros(len(fft))
    for i in range(len(fft)):
        r[i] = (abs(fft[i])**2 - alpha * means_power[i])
        if r[i] < beta*means_power[i]:
            r[i] = beta * means_power[i]
#        else:
#            r[i] = numpy.sqrt(r[i])
        #print r_orig[i], means_full[i], r[i]
    r = numpy.sqrt(r)

    reconstructed = ( r * numpy.cos(theta)
        + r * numpy.sin(theta)*1j);

    rec_abs = abs(reconstructed)[:len(reconstructed)/2+1]
    #print r_abs

    rec_db = stft.amplitude2db( rec_abs / length )


    reconstructed_sig = scipy.fftpack.ifft(reconstructed )

    reconstructed_sig /= window
    reconstructed_sig = numpy.real(reconstructed_sig)

    median_sig = scipy.signal.medfilt(rec_db, 5)
    median_sig_orig = scipy.signal.medfilt(fft_db, 5)

    if False:
    #if True:
        #pylab.plot(freqs, noise_db, label="mean noise")
        pylab.plot(freqs, fft_db, label="sig orig")
        pylab.plot(freqs, rec_db,
            label="reconstructed")
        pylab.plot(freqs, median_sig_orig,
            label="median orig")
        pylab.plot(freqs, median_sig,
            label="median rec.")
        pylab.legend()
        pylab.show()


    return reconstructed_sig 
예제 #19
0
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()
예제 #20
0
def calc_harmonics(wav_filename, f0=None, B=None,
        limit=defs.TOTAL_HARMONICS):
    if f0 is None:
        raise Exception("need f0 and B; run another program")

    # eliminate $HOME ~ and symlinks
    wav_filename = os.path.realpath(os.path.expanduser(wav_filename))
    basename = os.path.splitext(os.path.basename(wav_filename))[0]
    shared_dirname = os.path.abspath(
        os.path.join(os.path.dirname(wav_filename), '..'))

    dest_dir = os.path.join(shared_dirname, "spectrum", basename)
    if not os.path.exists(dest_dir):
        os.makedirs(dest_dir)

    window_buffers, sample_rate = stft.get_buffers_from_file(wav_filename)

    freqs = [ stft.bin2hertz(i, sample_rate)
        for i in range(stft.WINDOWSIZE/2+1) ]

    ### get noise for tuning off low harmonics
    initial_noise_floor, initial_noise_freqs, _, _, _ = calc_noise.get_noise(wav_filename)
    noise_cutoff = stft.db2amplitude(
        stft.amplitude2db(initial_noise_floor)
        +defs.STFT_MIN_DB_ABOVE_NOISE)

    bin_f0 = stft.hertz2bin(f0, sample_rate)
    # radius of search area for peaks
    bin_spread_below = int(
        stft.hertz2bin(defs.STFT_PEAK_SPREAD_BELOW_HERTZ*f0,
            sample_rate))
    bin_spread_above = int(
        stft.hertz2bin(defs.STFT_PEAK_SPREAD_ABOVE_HERTZ*f0,
            sample_rate))
    bin_spread_below = 3
    bin_spread_above = 3

    if defs.STFT_DUMP_TEXT:
        write_data.write_Bs(dest_dir, sample_rate, f0, B, limit,
            bin_spread_below, bin_spread_above)
        write_data.write_ideals(dest_dir, f0, limit)


    # store the peaks
    harmonics = [None]*limit

    spectrums = []
    table_info = tables.save_fft(basename)
    if table_info:
        harms_freqs = []
        harms_mags = []

    if defs.ONLY_N_WINDOWS:
        window_buffers = window_buffers[:defs.ONLY_N_WINDOWS]
    for window_number, window_buffer in enumerate(window_buffers):
        #print '-------- window --- %i' % window_number
        #fft_amplitude = stft.stft(window_buffer)
        fft_amplitude = stft.stft_amplitude(window_buffer)
        if window_number == 0:
            write_data.write_spectrum(dest_dir, window_number,
                freqs, stft.amplitude2db(fft_amplitude))
        if defs.STFT_DUMP_TEXT:
            write_data.write_spectrum(dest_dir, window_number,
            freqs, stft.amplitude2db(fft_amplitude))
        spectrums.append(fft_amplitude)

        # get harmonic peaks, and disable harmonics if can't do
        harms, _ = partials.get_freqs_mags(
            limit, bin_f0, B, fft_amplitude,
            bin_spread_below, bin_spread_above,
            only_peaks=False)
        if defs.STFT_PLOT_PARTIALS:
            plots.plot_partials(fft_amplitude, sample_rate, harms,
                bin_f0, B, bin_spread_below, bin_spread_above
                )
        if defs.STFT_DUMP_TEXT:
            dump_freqs = numpy.zeros(limit)
            dump_mags = numpy.zeros(limit)
        if table_info:
            harm_freqs = []
            harm_mags = []

        for h in harms:
            i = h.n-1
            if harmonics[i] is None:
                #print stft.bin2hertz(h.fft_bin, sample_rate), h.mag, noise_cutoff[h.fft_bin]
                harmonics[i] = classes.HarmonicSignal(h.n)
                #if use_harmonic(h, noise_cutoff, fft_amplitude,
                #        bin_f0, B,
                #        bin_spread_below, bin_spread_above,
                #        ):
                #    harmonics[i] = classes.HarmonicSignal(h.n)
                #else:
                #    #print "disable harmonic ", n
                #    harmonics[i] = False
            if harmonics[i] is not False:
                if h.mag == 0:
                    continue
                if defs.STFT_DUMP_TEXT:
                    dump_freqs[i] = stft.bin2hertz(h.fft_bin, sample_rate)
                    dump_mags[i] = h.mag
                if table_info:
                    harm_freqs.append(stft.bin2hertz(h.fft_bin, sample_rate))
                    harm_mags.append(h.mag)
                harmonics[i].mags.append(h.mag)
                harmonics[i].frame_numbers.append(window_number)
            #print harmonics[i]
        if table_info:
            harms_freqs.append(harm_freqs)
            harms_mags.append(harm_mags)

        if defs.STFT_DUMP_TEXT:
            #print dump_mags
            write_data.write_harms(dest_dir, window_number,
               dump_freqs, dump_mags, harmonics)

        if (defs.STFT_PLOT_FIRST_N > 0) and (window_number < defs.STFT_PLOT_FIRST_N):
            plots.plot_stft_first_n(window_number,
                defs.STFT_PLOT_FIRST_N,
                fft_amplitude, sample_rate, harms, wav_filename,
                bin_f0, B, bin_spread_below, bin_spread_above
                )
            if window_number >= defs.STFT_PLOT_FIRST_N - 1:
                pylab.show()
    dh = float(defs.HOPSIZE) / sample_rate
    if defs.STFT_DUMP_ALL:
        write_data.write_stft_all(dest_dir, spectrums, freqs, dh)
    table_info = tables.save_fft(basename)
    if table_info:
        for ti in table_info:
            write_data.write_stft_3d(basename, spectrums, freqs, dh,
                ti, harms_freqs, harms_mags, sample_rate)

    # clean up harmonics
    harmonics = filter(lambda x: x is not False, harmonics)
    for h in harmonics:
        h.mags = numpy.array(h.mags)
        h.frame_numbers = numpy.array(h.frame_numbers)
        #pylab.plot(stft.amplitude2db(h.mags))
        #pylab.show()

    return harmonics, dh
예제 #21
0
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()
예제 #22
0
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