Maria@4
|
1 # -*- coding: utf-8 -*-
|
Maria@4
|
2 """
|
Maria@4
|
3 Created on Tue Feb 2 22:26:10 2016
|
Maria@4
|
4
|
Maria@4
|
5 @author: mariapanteli
|
Maria@4
|
6 """
|
Maria@4
|
7 import smoothiecore as s
|
Maria@4
|
8 import numpy
|
Maria@4
|
9 import scipy.signal
|
Maria@4
|
10 # import librosa
|
Maria@4
|
11
|
Maria@4
|
12
|
Maria@4
|
13 class PitchBihist:
|
Maria@4
|
14 def __init__(self, win2sec=8):
|
Maria@4
|
15 self.y = None
|
Maria@4
|
16 self.sr = None
|
Maria@4
|
17 self.chroma = None
|
Maria@4
|
18 self.chromasr = None
|
Maria@4
|
19 self.bihist = None
|
Maria@4
|
20 self.win2sec = win2sec
|
Maria@4
|
21
|
Maria@4
|
22 def bihist_from_chroma(self, filename='test.wav', secondframedecomp=True):
|
Maria@4
|
23 self.chroma, self.chromasr = s.get_smoothie_for_bihist(filename=filename, hopinsec=0.005)
|
Maria@4
|
24 if secondframedecomp:
|
Maria@4
|
25 win2 = int(round(8*self.chromasr))
|
Maria@4
|
26 hop2 = int(round(0.5*self.chromasr))
|
Maria@4
|
27 nbins, norigframes = self.chroma.shape
|
Maria@4
|
28 if norigframes<win2:
|
Maria@4
|
29 nframes = 1
|
Maria@4
|
30 else:
|
Maria@4
|
31 nframes = int(1+numpy.floor((norigframes-win2)/float(hop2)))
|
Maria@4
|
32 bihistframes = numpy.empty((nbins*nbins, nframes))
|
Maria@4
|
33 for i in range(nframes): # loop over all 8-sec frames
|
Maria@4
|
34 frame = self.chroma[:, (i*hop2):min((i*hop2+win2),norigframes)]
|
Maria@4
|
35 bihist = self.bihistogram(frame)
|
Maria@4
|
36 bihist = numpy.reshape(bihist, -1)
|
Maria@4
|
37 bihistframes[:, i] = bihist
|
Maria@4
|
38 self.bihist = bihistframes
|
Maria@4
|
39 else:
|
Maria@4
|
40 self.bihist = numpy.reshape(self.bihistogram(), -1)
|
Maria@4
|
41
|
Maria@4
|
42 def bihist_from_melodia(self, filename='sample_melodia.csv', secondframedecomp=True, stop_sec=None):
|
Maria@4
|
43 def hz_to_cents(freq_Hz, ref_Hz=32.703, n_cents=1200):
|
Maria@4
|
44 """ convert frequency values from Hz to cents
|
Maria@4
|
45 reference frequency at C1
|
Maria@4
|
46 """
|
Maria@4
|
47 freq_cents = numpy.round(n_cents * numpy.log2(freq_Hz/ref_Hz))
|
Maria@4
|
48 return freq_cents
|
Maria@4
|
49 def wrap_to_octave(cents, octave_length=1200):
|
Maria@4
|
50 """ wrap to a single octave 0-1200
|
Maria@4
|
51 """
|
Maria@4
|
52 octave_cents = cents % octave_length
|
Maria@4
|
53 return octave_cents
|
Maria@4
|
54
|
Maria@4
|
55 n_bins = 60
|
Maria@4
|
56 data = numpy.loadtxt(filename, delimiter=',')
|
Maria@4
|
57 times, freqs = (data[:, 0], data[:, 1])
|
Maria@4
|
58 self.chromasr = 1. / (times[1] - times[0])
|
Maria@4
|
59 #self.chromasr = 128.
|
Maria@4
|
60 if stop_sec is not None:
|
Maria@4
|
61 stop_idx = numpy.where(times < stop_sec)[0]
|
Maria@4
|
62 times, freqs = times[stop_idx], freqs[stop_idx]
|
Maria@4
|
63 freqs[freqs<=0] = numpy.nan
|
Maria@4
|
64 #melody = freqs[freqs>0]
|
Maria@4
|
65 melody = freqs
|
Maria@4
|
66 n_frames = len(melody)
|
Maria@4
|
67 melody_cents = hz_to_cents(melody, n_cents=n_bins)
|
Maria@4
|
68 melody_octave = wrap_to_octave(melody_cents, octave_length=n_bins)
|
Maria@4
|
69 melody_matrix = numpy.zeros((n_bins, n_frames))
|
Maria@4
|
70 for time, pitch in enumerate(melody_octave):
|
Maria@4
|
71 if not numpy.isnan(pitch):
|
Maria@4
|
72 melody_matrix[int(pitch), time] = 1
|
Maria@4
|
73 if secondframedecomp:
|
Maria@4
|
74 win2 = int(round(self.win2sec*self.chromasr))
|
Maria@4
|
75 hop2 = int(round(0.5*self.chromasr))
|
Maria@4
|
76 nbins, norigframes = melody_matrix.shape
|
Maria@4
|
77 if norigframes<win2:
|
Maria@4
|
78 nframes = 1
|
Maria@4
|
79 win2 = norigframes
|
Maria@4
|
80 else:
|
Maria@4
|
81 nframes = int(1+numpy.floor((norigframes-win2)/float(hop2)))
|
Maria@4
|
82 bihistframes = numpy.empty((nbins*nbins, nframes))
|
Maria@4
|
83 for i in range(nframes): # loop over all 8-sec frames
|
Maria@4
|
84 frame = melody_matrix[:, (i*hop2):(i*hop2+win2)]
|
Maria@4
|
85 bihist = self.bihistogram(frame)
|
Maria@4
|
86 bihist = numpy.reshape(bihist, -1)
|
Maria@4
|
87 bihistframes[:, i] = bihist
|
Maria@4
|
88 self.bihist = bihistframes
|
Maria@4
|
89 else:
|
Maria@4
|
90 self.bihist = self.bihistogram(melody_matrix)
|
Maria@4
|
91 return self.bihist
|
Maria@4
|
92
|
Maria@4
|
93 def bihistogram(self, spec, winsec=0.5, align=True):
|
Maria@4
|
94 win = int(round(winsec*self.chromasr))
|
Maria@4
|
95 ker = numpy.concatenate([numpy.zeros((win, 1)), numpy.ones((win+1, 1))], axis=0)
|
Maria@4
|
96 spec = spec.T # transpose to have franes as rows in convolution
|
Maria@4
|
97
|
Maria@4
|
98 # energy threshold
|
Maria@4
|
99 thr = 0.3*numpy.max(spec)
|
Maria@4
|
100 spec[spec < max(thr, 0)] = 0
|
Maria@4
|
101
|
Maria@4
|
102 # transitions via convolution
|
Maria@4
|
103 tra = scipy.signal.convolve2d(spec, ker, mode='same')
|
Maria@4
|
104 tra[spec > 0] = 0
|
Maria@4
|
105
|
Maria@4
|
106 # multiply with original
|
Maria@4
|
107 B = numpy.dot(tra.T, spec)
|
Maria@4
|
108
|
Maria@4
|
109 # normalize
|
Maria@4
|
110 mxB = numpy.max(B)
|
Maria@4
|
111 mnB = numpy.min(B)
|
Maria@4
|
112 if mxB != mnB:
|
Maria@4
|
113 B = (B - mnB)/float(mxB-mnB)
|
Maria@4
|
114
|
Maria@4
|
115 # circshift to highest?
|
Maria@4
|
116 if align:
|
Maria@4
|
117 ref = numpy.argmax(numpy.sum(spec, axis=0))
|
Maria@4
|
118 B = numpy.roll(B, -ref, axis=0)
|
Maria@4
|
119 B = numpy.roll(B, -ref, axis=1)
|
Maria@4
|
120 return B
|
Maria@4
|
121
|
Maria@4
|
122 def bihist_from_precomp_chroma(self, align=False):
|
Maria@4
|
123 win2 = int(round(self.win2sec*self.chromasr))
|
Maria@4
|
124 hop2 = int(round(0.5*self.chromasr))
|
Maria@4
|
125 nbins, norigframes = self.chroma.shape
|
Maria@4
|
126 if norigframes<win2:
|
Maria@4
|
127 nframes = 1
|
Maria@4
|
128 else:
|
Maria@4
|
129 nframes = int(1+numpy.floor((norigframes-win2)/float(hop2)))
|
Maria@4
|
130 bihistframes = numpy.empty((nbins*nbins, nframes))
|
Maria@4
|
131 for i in range(nframes): # loop over all 8-sec frames
|
Maria@4
|
132 frame = self.chroma[:, (i*hop2):min((i*hop2+win2),norigframes)]
|
Maria@4
|
133 bihist = self.bihistogram(frame, align=align)
|
Maria@4
|
134 bihist = numpy.reshape(bihist, -1)
|
Maria@4
|
135 bihistframes[:, i] = bihist
|
Maria@4
|
136 self.bihist = bihistframes
|
Maria@4
|
137
|
Maria@4
|
138 def get_pitchbihist(self, filename='test.wav'):
|
Maria@4
|
139 self.bihist_from_chroma(filename=filename)
|
Maria@4
|
140 return self.bihist
|
Maria@4
|
141
|
Maria@4
|
142 def get_pitchbihist_from_chroma(self, chroma=[], chromasr=[]):
|
Maria@4
|
143 self.chroma = chroma
|
Maria@4
|
144 self.chromasr = chromasr
|
Maria@4
|
145 self.bihist_from_precomp_chroma(align=False)
|
Maria@4
|
146 return self.bihist
|
Maria@4
|
147
|
Maria@4
|
148
|
Maria@4
|
149 if __name__ == '__main__':
|
Maria@4
|
150 pb = PitchBihist()
|
Maria@4
|
151 pb.get_pitchbihist()
|