annotate scripts/OPMellin.py @ 4:e50c63cf96be branch-tests

rearranging folders
author Maria Panteli
date Mon, 11 Sep 2017 11:51:50 +0100
parents
children e5e8e8a96948
rev   line source
Maria@4 1 # -*- coding: utf-8 -*-
Maria@4 2 """
Maria@4 3 Created on Mon Aug 17 13:37:00 2015
Maria@4 4
Maria@4 5 @author: mariapanteli
Maria@4 6 """
Maria@4 7
Maria@4 8 import librosa
Maria@4 9 import scipy.signal
Maria@4 10 # import matplotlib.pyplot as plt
Maria@4 11 import numpy
Maria@4 12
Maria@4 13 class OPMellin:
Maria@4 14 def __init__(self, win2sec=8):
Maria@4 15 self.y = None
Maria@4 16 self.sr = None
Maria@4 17 self.melspec = None
Maria@4 18 self.melsr = None
Maria@4 19 self.op = None
Maria@4 20 self.opmellin = None
Maria@4 21 self.win2sec = win2sec
Maria@4 22
Maria@4 23 def load_audiofile(self, filename='test.wav', sr=None, segment=True):
Maria@4 24 self.y, self.sr = librosa.load(filename, sr=sr)
Maria@4 25 #self.y, self.sr = librosa.load(filename) # default sr=22050
Maria@4 26 if segment:
Maria@4 27 tracklength = self.y.shape[0]/float(self.sr)
Maria@4 28 startSample = 0
Maria@4 29 endSample = None
Maria@4 30 if tracklength > 90:
Maria@4 31 startPointSec = (tracklength/2.)-20
Maria@4 32 startSample = round(startPointSec*self.sr)
Maria@4 33 endSample = startSample+45*self.sr
Maria@4 34 self.y = self.y[startSample:endSample]
Maria@4 35
Maria@4 36
Maria@4 37 # def mel_spectrogram(self, y=None, sr=None, filename='1_21.wav'):
Maria@4 38 def mel_spectrogram(self, y=None, sr=None):
Maria@4 39 if self.y is None:
Maria@4 40 self.y = y
Maria@4 41 if self.sr is None:
Maria@4 42 self.sr = sr
Maria@4 43 win1 = int(round(0.04*self.sr))
Maria@4 44 hop1 = int(round(win1/8.))
Maria@4 45 nfft1 = int(2**numpy.ceil(numpy.log2(win1)))
Maria@4 46 nmels = 40
Maria@4 47 # y, sr = librosa.load(filename, sr=fs)
Maria@4 48 # melspec = librosa.feature.melspectrogram(y=y, sr=sr, n_fft=nfft, win_length=win1, window=scipy.signal.hamming, hop_length=hop1, n_mels=nmels)
Maria@4 49 # melspec = librosa.feature.melspectrogram(y=self.y, sr=self.sr, n_fft=nfft, hop_length=hop1, n_mels=nmels)
Maria@4 50 D = numpy.abs(librosa.stft(self.y, n_fft=nfft1, hop_length=hop1, win_length=win1, window=scipy.signal.hamming))**2
Maria@4 51 #melspec = librosa.feature.melspectrogram(S=D, sr=self.sr, n_mels=nmels)
Maria@4 52 melspec = librosa.feature.melspectrogram(S=D, sr=self.sr, n_mels=nmels, fmax=8000)
Maria@4 53 melsr = self.sr/float(hop1)
Maria@4 54 # librosa.display.specshow(melspec)
Maria@4 55 # return melspec, melsr
Maria@4 56 self.melspec = melspec
Maria@4 57 self.melsr = melsr
Maria@4 58
Maria@4 59 # post process spectrogram
Maria@4 60 def post_process_spec(self, melspec=None, log=True, medianfilt=False, sqrt=False, smooth=False, diff=True, subtractmean=True, halfwave=True, maxnormal=True):
Maria@4 61 if self.melspec is None:
Maria@4 62 self.melspec = melspec
Maria@4 63 if log:
Maria@4 64 self.melspec = librosa.logamplitude(self.melspec)
Maria@4 65 if medianfilt:
Maria@4 66 ks = int(0.1 * self.melsr) # 100ms kernel size
Maria@4 67 if ks % 2 == 0: # ks must be odd
Maria@4 68 ks += 1
Maria@4 69 nmels = self.melspec.shape[0]
Maria@4 70 for i in range(nmels):
Maria@4 71 self.melspec[i,:] = scipy.signal.medfilt(self.melspec[i,:],kernel_size = ks)
Maria@4 72 if sqrt:
Maria@4 73 self.melspec = self.melspec**.5
Maria@4 74 if smooth:
Maria@4 75 step = 50.0
Maria@4 76 nmels = self.melspec.shape[0]
Maria@4 77 mm = self.melspec
Maria@4 78 for i in range(nmels):
Maria@4 79 mm[i,:] = numpy.convolve(mm[i,:], numpy.ones(step)/step, mode='same')
Maria@4 80 self.melspec = mm
Maria@4 81 if diff:
Maria@4 82 self.melspec = numpy.concatenate((self.melspec,self.melspec[:,-1,None]),axis=1) # append one frame before diff to keep number of frames the same
Maria@4 83 self.melspec = numpy.diff(self.melspec, n=1, axis=1)
Maria@4 84 if subtractmean:
Maria@4 85 mean = self.melspec.mean(axis=1)
Maria@4 86 mean.shape = (mean.shape[0], 1)
Maria@4 87 self.melspec = self.melspec - mean
Maria@4 88 if halfwave:
Maria@4 89 self.melspec[numpy.where(self.melspec < 0)] = 0
Maria@4 90 if maxnormal:
Maria@4 91 if self.melspec.max() != 0: # avoid division by 0
Maria@4 92 self.melspec = self.melspec/self.melspec.max()
Maria@4 93 # return melspec
Maria@4 94
Maria@4 95
Maria@4 96 def onset_patterns(self, melspec=None, melsr=None, fft=True, logfilter=False, center=True, bpmrange=True):
Maria@4 97 if self.melspec is None:
Maria@4 98 self.melspec = melspec
Maria@4 99 if self.melsr is None:
Maria@4 100 self.melsr = melsr
Maria@4 101 win2 = int(round(self.win2sec*self.melsr))
Maria@4 102 hop2 = int(round(0.5*self.melsr))
Maria@4 103 nmels, nmelframes = self.melspec.shape
Maria@4 104 if fft: # periodicity via fft
Maria@4 105 #nfft2 = int(2**numpy.ceil(numpy.log2(win2)))
Maria@4 106 nfft2 = 2048 # nfft2 does not depend on win2??
Maria@4 107 melspectemp = self.melspec
Maria@4 108 if ((nfft2 > win2) and (center is False)):
Maria@4 109 # pad the signal by nfft2-win2 so that frame decomposition (n_frames)
Maria@4 110 # is still based on win2 and not nfft2
Maria@4 111 melspectemp = numpy.concatenate([numpy.zeros((nmels,int((nfft2 - win2) // 2))),self.melspec, numpy.zeros((nmels,int((nfft2 - win2) // 2)))],axis=1)
Maria@4 112 if melspectemp.shape[1]<nfft2:
Maria@4 113 # pad with zeros to have at least one 8-sec window
Maria@4 114 nzeros = nfft2 - melspectemp.shape[1]
Maria@4 115 melspectemp = numpy.concatenate([numpy.zeros((nmels,int(numpy.ceil(nzeros / 2.)))),melspectemp, numpy.zeros((nmels,int(numpy.ceil(nzeros / 2.))))],axis=1)
Maria@4 116 #melspectemp = numpy.concatenate([melspectemp, numpy.zeros((nmels,nzeros))],axis=1)
Maria@4 117 # nframes = int(round(numpy.ceil(round(nmelframes/hop2))))
Maria@4 118 ff0 = numpy.abs(librosa.stft(y=melspectemp[0, :], win_length=win2, hop_length=hop2, n_fft=nfft2, window=scipy.signal.hamming, center=center))
Maria@4 119 nframes = ff0.shape[1]
Maria@4 120 # nmags, nframes = ff0.shape
Maria@4 121 if logfilter: # log filterbank
Maria@4 122 nbins = 25
Maria@4 123 binsperoct = 5
Maria@4 124 fft2 = numpy.zeros((nmels, nbins, nframes))
Maria@4 125 logfb = librosa.filters.logfrequency(self.melsr, nfft2, n_bins=nbins, bins_per_octave=binsperoct, fmin=0.5)
Maria@4 126 # logfb = librosa.filters.logfrequency(self.melsr, nfft2, n_bins=25, bins_per_octave=5, fmin=0.5)
Maria@4 127 for i in range(nmels):
Maria@4 128 fftmags = numpy.abs(librosa.stft(y=melspectemp[i, :], win_length=win2, hop_length=hop2, n_fft=nfft2, window=scipy.signal.hamming, center=center))
Maria@4 129 fftmags = numpy.dot(logfb, fftmags) # log
Maria@4 130 fft2[i, :, :] = fftmags
Maria@4 131 else:
Maria@4 132 # nmags = min(round(nfft2/2), 200)
Maria@4 133 if bpmrange:
Maria@4 134 # freqresinbpm = float(self.melsr)/float(nfft2)*60.
Maria@4 135 freqresinbpm = float(self.melsr)/float(nfft2/2.)*60.
Maria@4 136 minmag = int(numpy.floor(30./freqresinbpm)) # min tempo 30bpm
Maria@4 137 maxmag = int(numpy.ceil(960./freqresinbpm)) # max tempo 960 bpm
Maria@4 138 magsinds = range(minmag, maxmag)
Maria@4 139 else:
Maria@4 140 magsinds = range(0, 200)
Maria@4 141 nmags = len(magsinds)
Maria@4 142 fft2 = numpy.zeros((nmels, nmags, nframes))
Maria@4 143 for i in range(nmels):
Maria@4 144 fftmags = numpy.abs(librosa.stft(y=melspectemp[i, :], win_length=win2, hop_length=hop2, n_fft=nfft2, window=scipy.signal.hamming, center=center))
Maria@4 145 fftmags = fftmags[magsinds, :]
Maria@4 146 fft2[i, :, :] = fftmags
Maria@4 147 op = fft2
Maria@4 148 else: # periodicity via autocorrelation
Maria@4 149 nmags = min(win2, 1000)
Maria@4 150 if nmelframes < win2:
Maria@4 151 nframes = 1
Maria@4 152 else:
Maria@4 153 nframes = int(nmelframes/float(win2))
Maria@4 154 autocor = numpy.zeros((nmels, nmags, nframes))
Maria@4 155 for i in range(nmels):
Maria@4 156 ac = numpy.zeros((nmags, nframes))
Maria@4 157 for j in range(nframes):
Maria@4 158 ac[:, j] = librosa.autocorrelate(self.melspec[i, (j*win2):min((j+1)*win2, nmelframes)], max_size=nmags)
Maria@4 159 autocor[i, :, :] = ac
Maria@4 160 op = autocor
Maria@4 161 self.op = op
Maria@4 162
Maria@4 163 def post_process_op(self, medianfiltOP=False):
Maria@4 164 if medianfiltOP:
Maria@4 165 hop2 = int(round(0.5*self.melsr))
Maria@4 166 ssr = self.melsr/float(hop2)
Maria@4 167 ks = int(0.5 * ssr) # 100ms kernel size
Maria@4 168 if ks % 2 == 0: # ks must be odd
Maria@4 169 ks += 1
Maria@4 170 nmels, nmags, nframes = self.op.shape
Maria@4 171 for i in range(nmels):
Maria@4 172 for j in range(nframes):
Maria@4 173 #self.op[i,:,j] = scipy.signal.medfilt(self.op[i,:,j],kernel_size = ks)
Maria@4 174 self.op[i,:,j] = numpy.convolve(self.op[i,:,j], numpy.ones(ks)/ks, mode='same')
Maria@4 175
Maria@4 176 def mellin_transform(self, op=None):
Maria@4 177 if self.op is None:
Maria@4 178 self.op = op
Maria@4 179 nmels, nmags, nframes = self.op.shape
Maria@4 180 #nmagsout = min(200, nmags)
Maria@4 181 nmagsout = 200
Maria@4 182 u_max = numpy.log(nmags)
Maria@4 183 delta_c = numpy.pi / u_max
Maria@4 184 c_max = nmagsout
Maria@4 185 c = numpy.arange(delta_c, c_max, delta_c)
Maria@4 186 k = range(1, nmags)
Maria@4 187 exponent = 0.5 - c*1j
Maria@4 188
Maria@4 189 normMat = 1./(exponent * numpy.sqrt(2*numpy.pi))
Maria@4 190 normMat.shape = (normMat.shape[0], 1)
Maria@4 191 normMat = numpy.repeat(normMat.T, nmels, axis=0)
Maria@4 192 kernelMat = numpy.asarray([numpy.power(ki, exponent) for ki in k])
Maria@4 193 opmellin = numpy.zeros((nmels, nmagsout, nframes))
Maria@4 194 for i in range(nframes):
Maria@4 195 self.op[:, -1, i] = 0
Maria@4 196 deltaMat = - numpy.diff(self.op[:, :, i])
Maria@4 197 mellin = numpy.abs(numpy.dot(deltaMat, kernelMat) * normMat)
Maria@4 198 opmellin[:, :, i] = mellin[:, :nmagsout]
Maria@4 199 self.opmellin = opmellin
Maria@4 200
Maria@4 201
Maria@4 202 def post_process_opmellin(self, opmellin=None, aveFreq=False, normFrame=True):
Maria@4 203 if self.opmellin is None:
Maria@4 204 self.opmellin = opmellin
Maria@4 205 if aveFreq:
Maria@4 206 self.opmellin = numpy.mean(self.opmellin, axis=0)
Maria@4 207 else: # just reshape
Maria@4 208 nmels, nmags, nframes = self.opmellin.shape
Maria@4 209 self.opmellin = self.opmellin.reshape((nmels*nmags, nframes))
Maria@4 210 if normFrame:
Maria@4 211 min_opmellin = numpy.amin(self.opmellin, axis=0, keepdims=True)
Maria@4 212 max_opmellin = numpy.amax(self.opmellin, axis=0, keepdims=True)
Maria@4 213 denom = max_opmellin - min_opmellin
Maria@4 214 denom[denom==0] = 1 # avoid division by 0 if frame is all 0s-silent
Maria@4 215 self.opmellin = (self.opmellin - min_opmellin) / denom
Maria@4 216
Maria@4 217
Maria@4 218 def get_opmellin(self, filename='test.wav', logfilter=False, center=True, medianfiltspec=False, medianfiltOP=False):
Maria@4 219 self.load_audiofile(filename=filename)
Maria@4 220 self.mel_spectrogram()
Maria@4 221 #self.post_process_spec(medianfilt=medianfiltspec)
Maria@4 222 self.post_process_spec(log=False, sqrt=True, medianfilt=medianfiltspec) # sqrt seems to work better
Maria@4 223 self.onset_patterns(logfilter=logfilter, center=center)
Maria@4 224 self.post_process_op(medianfiltOP=medianfiltOP)
Maria@4 225 self.mellin_transform()
Maria@4 226 self.post_process_opmellin()
Maria@4 227 return self.opmellin
Maria@4 228
Maria@4 229 def get_opmellin_from_melspec(self, melspec=[], melsr=[]):
Maria@4 230 self.melspec = melspec
Maria@4 231 self.melsr = melsr
Maria@4 232 self.post_process_spec(log=False, sqrt=True, medianfilt=True) # sqrt seems to work better
Maria@4 233 self.onset_patterns(logfilter=False, center=False)
Maria@4 234 self.post_process_op(medianfiltOP=True)
Maria@4 235 self.mellin_transform()
Maria@4 236 self.post_process_opmellin()
Maria@4 237 return self.opmellin
Maria@4 238
Maria@4 239 if __name__ == '__main__':
Maria@4 240 op = OPMellin()
Maria@4 241 op.get_opmellin()