[7175ed4] | 1 | #! /usr/bin/env python |
---|
[89fd1e5] | 2 | |
---|
[a4575c4] | 3 | import sys, os.path |
---|
[4120fbc] | 4 | from aubio import pvoc, source, float_type |
---|
[b3c2d33] | 5 | from numpy import zeros, log10, vstack |
---|
[a4575c4] | 6 | import matplotlib.pyplot as plt |
---|
[89fd1e5] | 7 | |
---|
[9f8e8a9] | 8 | def get_spectrogram(filename, samplerate = 0): |
---|
[a4575c4] | 9 | win_s = 512 # fft window size |
---|
[4120fbc] | 10 | hop_s = win_s // 2 # hop size |
---|
| 11 | fft_s = win_s // 2 + 1 # spectrum bins |
---|
[b1c2acc] | 12 | |
---|
[a4575c4] | 13 | a = source(filename, samplerate, hop_s) # source file |
---|
| 14 | if samplerate == 0: samplerate = a.samplerate |
---|
| 15 | pv = pvoc(win_s, hop_s) # phase vocoder |
---|
[4120fbc] | 16 | specgram = zeros([0, fft_s], dtype=float_type) # numpy array to store spectrogram |
---|
[b1c2acc] | 17 | |
---|
[a4575c4] | 18 | # analysis |
---|
| 19 | while True: |
---|
| 20 | samples, read = a() # read file |
---|
| 21 | specgram = vstack((specgram,pv(samples).norm)) # store new norm vector |
---|
| 22 | if read < a.hop_size: break |
---|
[89fd1e5] | 23 | |
---|
[a4575c4] | 24 | # plotting |
---|
| 25 | fig = plt.imshow(log10(specgram.T + .001), origin = 'bottom', aspect = 'auto', cmap=plt.cm.gray_r) |
---|
| 26 | ax = fig.axes |
---|
| 27 | ax.axis([0, len(specgram), 0, len(specgram[0])]) |
---|
| 28 | # show axes in Hz and seconds |
---|
| 29 | time_step = hop_s / float(samplerate) |
---|
| 30 | total_time = len(specgram) * time_step |
---|
[4120fbc] | 31 | outstr = "total time: %0.2fs" % total_time |
---|
| 32 | print(outstr + ", samplerate: %.2fkHz" % (samplerate / 1000.)) |
---|
[a4575c4] | 33 | n_xticks = 10 |
---|
| 34 | n_yticks = 10 |
---|
[4db10ad] | 35 | |
---|
[a4575c4] | 36 | def get_rounded_ticks( top_pos, step, n_ticks ): |
---|
| 37 | top_label = top_pos * step |
---|
| 38 | # get the first label |
---|
| 39 | ticks_first_label = top_pos * step / n_ticks |
---|
| 40 | # round to the closest .1 |
---|
| 41 | ticks_first_label = round ( ticks_first_label * 10. ) / 10. |
---|
| 42 | # compute all labels from the first rounded one |
---|
| 43 | ticks_labels = [ ticks_first_label * n for n in range(n_ticks) ] + [ top_label ] |
---|
| 44 | # get the corresponding positions |
---|
| 45 | ticks_positions = [ ticks_labels[n] / step for n in range(n_ticks) ] + [ top_pos ] |
---|
| 46 | # convert to string |
---|
| 47 | ticks_labels = [ "%.1f" % x for x in ticks_labels ] |
---|
| 48 | # return position, label tuple to use with x/yticks |
---|
| 49 | return ticks_positions, ticks_labels |
---|
| 50 | |
---|
| 51 | # apply to the axis |
---|
| 52 | x_ticks, x_labels = get_rounded_ticks ( len(specgram), time_step, n_xticks ) |
---|
| 53 | y_ticks, y_labels = get_rounded_ticks ( len(specgram[0]), (samplerate / 1000. / 2.) / len(specgram[0]), n_yticks ) |
---|
| 54 | ax.set_xticks( x_ticks ) |
---|
| 55 | ax.set_yticks ( y_ticks ) |
---|
| 56 | ax.set_xticklabels( x_labels ) |
---|
| 57 | ax.set_yticklabels ( y_labels ) |
---|
| 58 | ax.set_ylabel('Frequency (kHz)') |
---|
| 59 | ax.set_xlabel('Time (s)') |
---|
[337aaae] | 60 | ax.set_title(os.path.basename(filename)) |
---|
[a4575c4] | 61 | for item in ([ax.title, ax.xaxis.label, ax.yaxis.label] + |
---|
| 62 | ax.get_xticklabels() + ax.get_yticklabels()): |
---|
| 63 | item.set_fontsize('x-small') |
---|
| 64 | return fig |
---|
[89fd1e5] | 65 | |
---|
[b1c2acc] | 66 | if __name__ == '__main__': |
---|
[a4575c4] | 67 | if len(sys.argv) < 2: |
---|
[4120fbc] | 68 | print("Usage: %s <filename>" % sys.argv[0]) |
---|
[67e16c2] | 69 | else: |
---|
| 70 | for soundfile in sys.argv[1:]: |
---|
| 71 | fig = get_spectrogram(soundfile) |
---|
| 72 | # display graph |
---|
[4120fbc] | 73 | plt.show() |
---|
[67e16c2] | 74 | #outimage = os.path.basename(soundfile) + '.png' |
---|
| 75 | #print ("writing: " + outimage) |
---|
| 76 | #plt.savefig(outimage) |
---|
| 77 | plt.close() |
---|