annotate vamp/HPspectrogram.py @ 19:890cfe424f4a tip

added annotations
author mitian
date Fri, 11 Dec 2015 09:47:40 +0000
parents ef1fd8b0f3c4
children
rev   line source
mi@2 1 import os, sys
mi@2 2 import numpy as np
mi@2 3 import scipy as sp
mi@2 4 from scipy.ndimage.filters import *
mi@2 5 from vampy import *
mi@2 6 from copy import deepcopy
mi@2 7
mi@2 8 class HPspectrogram:
mi@2 9
mi@2 10 def __init__(self, inputSampleRate):
mi@2 11
mi@2 12 # flags:
mi@2 13 self.vampy_flags = vf_DEBUG | vf_ARRAY | vf_REALTIME
mi@2 14 self.inputSampleRate = inputSampleRate
mi@2 15 self.stepSize = 1024
mi@2 16 self.blockSize = 2048
mi@2 17 self.channels = 1
mi@2 18 self.harmonic_medwin = 8
mi@2 19 self.percussive_medwin = 8
mi@2 20 self.harmonic_thresh = 0.5
mi@2 21 self.percussive_thresh = 0.5
mi@2 22 self.whitening_on = False
mi@2 23 self.whitenRelaxCoeff = 0.9997
mi@2 24 self.whitenFloor = 0.01
mi@2 25 self.magPeaks = None
mi@2 26
mi@2 27 def initialise(self, channels, stepSize, blockSize):
mi@2 28 self.channels = channels
mi@2 29 self.stepSize = stepSize
mi@2 30 self.blockSize = blockSize
mi@2 31 self.maglist = []
mi@2 32 self.timestamp = []
mi@2 33 return True
mi@2 34
mi@2 35 def reset(self):
mi@2 36 # reset any initial conditions
mi@2 37 self.maglist = []
mi@2 38 self.timestamp = []
mi@2 39 return None
mi@2 40
mi@2 41 def getMaker(self):
mi@2 42 return 'Mi Tian'
mi@2 43
mi@2 44 def getName(self):
mi@2 45 return 'Harmonic percussive spectrogram'
mi@2 46
mi@2 47 def getIdentifier(self):
mi@2 48 return 'hps'
mi@2 49
mi@2 50 def getDescription(self):
mi@2 51 return 'Harmonic and percussive emphasised spectrograms.'
mi@2 52
mi@2 53 def getCopyright(self):
mi@2 54 return ''
mi@2 55
mi@2 56 def getMaxChannelCount(self):
mi@2 57 return 1
mi@2 58
mi@2 59 def getInputDomain(self):
mi@2 60 return FrequencyDomain
mi@2 61
mi@2 62 def getOutputDescriptors(self):
mi@2 63
mi@2 64 #Generic values are the same for all
mi@2 65 Generic = OutputDescriptor()
mi@2 66 Generic.hasFixedBinCount=False
mi@2 67 Generic.hasKnownExtents=False
mi@2 68 Generic.isQuantized=False
mi@2 69 Generic.sampleType = OneSamplePerStep
mi@2 70 Generic.unit = 'Hz'
mi@2 71
mi@2 72 HSPEC = OutputDescriptor(Generic)
mi@2 73 HSPEC.identifier = 'gt'
mi@2 74 HSPEC.name = 'Harmonic emphasised spectrogram'
mi@2 75 HSPEC.description = 'Harmonic emphasised spectrogram'
mi@2 76 HSPEC.binCount = self.nBands
mi@2 77
mi@2 78 PSPEC = OutputDescriptor(Generic)
mi@2 79 PSPEC.identifier = 'gt'
mi@2 80 PSPEC.name = 'Percussive emphasised spectrogram'
mi@2 81 PSPEC.description = 'Percussive emphasised spectrogram'
mi@2 82
mi@2 83 return OutputList(HSPEC, PSPEC)
mi@2 84
mi@2 85 def getParameterDescriptors(self):
mi@2 86
mi@2 87 harmonic_thresh = ParameterDescriptor()
mi@2 88 harmonic_thresh.identifier='percussive_thresh'
mi@2 89 harmonic_thresh.name='percussive_thresh'
mi@2 90 harmonic_thresh.description='Binarisation threshold for harmonic emphasised magnitude spectrogram'
mi@2 91 harmonic_thresh.unit='v'
mi@2 92 harmonic_thresh.minValue=0
mi@2 93 harmonic_thresh.maxValue=1
mi@2 94 harmonic_thresh.defaultValue=0.5
mi@2 95 harmonic_thresh.isQuantized=False
mi@2 96
mi@2 97 percussive_thresh = ParameterDescriptor(harmonic_thresh)
mi@2 98 percussive_thresh.identifier='percussive_thresh'
mi@2 99 percussive_thresh.name='percussive_thresh'
mi@2 100 percussive_thresh.description='Binarisation threshold for percussive emphasised magnitude spectrogram'
mi@2 101
mi@2 102 harmonic_medwin = ParameterDescriptor()
mi@2 103 harmonic_medwin.identifier = 'harmonic_medwin'
mi@2 104 harmonic_medwin.description = 'Median window length for harmonic part.'
mi@2 105 harmonic_medwin.name = 'Median window length for harmonic part.'
mi@2 106 harmonic_medwin.minValue = 1
mi@2 107 harmonic_medwin.defaultValue = 8
mi@2 108 harmonic_medwin.maxValue = 15
mi@2 109 harmonic_medwin.isQuantized = True
mi@2 110
mi@2 111 percussive_medwin = ParameterDescriptor(harmonic_medwin)
mi@2 112 percussive_medwin.identifier = 'percussive_medwin'
mi@2 113 percussive_medwin.description = 'Median window length for percussive part.'
mi@2 114 percussive_medwin.name = 'Median window length for percussive part.'
mi@2 115
mi@2 116 boolDescriptor = ParameterDescriptor()
mi@2 117 boolDescriptor.isQuantized = True
mi@2 118 boolDescriptor.minValue= 0
mi@2 119 boolDescriptor.maxValue= 1
mi@2 120 boolDescriptor.quantizeStep = 1
mi@2 121
mi@2 122 whitening = ParameterDescriptor(boolDescriptor)
mi@2 123 whitening.identifier='whitening'
mi@2 124 whitening.name='Adaptive whitening'
mi@2 125 whitening.description='Turn adaptive whitening on or off'
mi@2 126 whitening.defaultValue = False
mi@2 127
mi@2 128 return ParameterList(harmonic_thresh, percussive_thresh, harmonic_medwin, percussive_medwin, whitening)
mi@2 129
mi@2 130 def setParameter(self, paramid, newval):
mi@2 131 if paramid == 'percussive_thresh' :
mi@2 132 self.percussive_thresh = newval
mi@2 133 if paramid == 'harmonic_medwin' :
mi@2 134 self.harmonic_medwin = newval
mi@2 135 if paramid == 'harmonic_medwin' :
mi@2 136 self.harmonic_medwin = newval
mi@2 137 if paramid == 'percussive_medwin' :
mi@2 138 self.percussive_medwin = newval
mi@2 139 if paramid == 'whitening' :
mi@2 140 self.whitening_on = newval == 1.0
mi@2 141
mi@2 142 return None
mi@2 143
mi@2 144 def getParameter(self, paramid):
mi@2 145 if paramid == 'percussive_thresh' :
mi@2 146 return self.percussive_thresh
mi@2 147 if paramid == 'harmonic_medwin' :
mi@2 148 return self.harmonic_medwin
mi@2 149 if paramid == 'percussive_medwin' :
mi@2 150 return self.percussive_medwin
mi@2 151 if paramid == 'harmonic_medwin' :
mi@2 152 return self.harmonic_medwin
mi@2 153 if paramid == 'whitening' :
mi@2 154 if self.whitening_on :
mi@2 155 return 1.0
mi@2 156 else :
mi@2 157 return 0.0
mi@2 158 else:
mi@2 159 return 0.0
mi@2 160
mi@2 161 def whiten(self, magnitudeSpectrogram):
mi@2 162 '''This function reproduces adaptive whitening as described in Dan Stowell's paper.'''
mi@2 163
mi@2 164 half_length = self.blockSize * 0.5 + 1.0
mi@2 165 nFrames = magnitudeSpectrogram.shape[0]
mi@2 166 whitened_ms = np.zeros_like(magnitudeSpectrogram)
mi@2 167
mi@2 168 if self.magPeaks is None :
mi@2 169 self.magPeaks = np.zeros(half_length, dtype = float32)
mi@2 170
mi@2 171 for i in xrange(nFrames):
mi@2 172 m = magnitudeSpectrogram[i, :]
mi@2 173 idx = m < self.magPeaks
mi@2 174 m[idx] += (self.magPeaks[idx] - m[idx]) * self.whitenRelaxCoeff
mi@2 175 m[m < self.whitenFloor] = self.whitenFloor
mi@2 176 self.magPeaks = m
mi@2 177
mi@2 178 whitened_ms[i, :] = magnitudeSpectrogram[i, :] / m
mi@2 179
mi@2 180 return whitened_ms
mi@2 181
mi@2 182 def process(self, inputbuffers, timestamp):
mi@2 183
mi@2 184 output_featureSet = FeatureSet()
mi@2 185 self.timestamp.append(timestamp)
mi@2 186 complexSpectrum = inputbuffers[0]
mi@2 187 magnitudeSpectrum = abs(complexSpectrum)
mi@2 188 self.maglist.append(magnitudeSpectrum)
mi@2 189
mi@2 190 return output_featureSet
mi@2 191
mi@2 192 def getRemainingFeatures(self):
mi@2 193
mi@2 194 output_featureSet = FeatureSet()
mi@2 195
mi@2 196 nFrames = len(self.maglist)
mi@2 197 magnitudeSpectrogram = np.array(self.maglist)
mi@2 198
mi@2 199 if self.whitening_on:
mi@2 200 magnitudeSpectrogram = self.whiten(magnitudeSpectrogram)
mi@2 201 else:
mi@2 202 magnitudeSpectrogram = (magnitudeSpectrogram - np.min(magnitudeSpectrogram)) / (np.max(magnitudeSpectrogram) - np.min(magnitudeSpectrogram))
mi@2 203
mi@2 204 harmonic_ma = median_filter(magnitudeSpectrogram, size=(self.harmonic_medwin, 1))
mi@2 205 percussive_ma = median_filter(magnitudeSpectrogram, size=(1, self.percussive_medwin))
mi@2 206
mi@2 207 harmonicSpectrogram = magnitudeSpectrogram * (harmonic_ma>=percussive_ma).astype(float)
mi@2 208 percussiveSpectrogram = magnitudeSpectrogram * (harmonic_ma<percussive_ma).astype(float)
mi@2 209
mi@2 210 output_featureSet[0] = flist0 = FeatureList()
mi@2 211 output_featureSet[1] = flist1 = FeatureList()
mi@2 212 for frame in xrange(nFrames):
mi@2 213 f = Feature(timestamp = self.timestamp[frame], values = ma_harmonicSpectrogram[frame, :])
mi@2 214 flist0.append(f)
mi@2 215 f = Feature(timestamp = self.timestamp[frame], values = ma_percussiveSpectrogram[frame, :])
mi@2 216 flist1.append(f)
mi@2 217
mi@2 218 return output_featureSet