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

added annotations
author mitian
date Fri, 11 Dec 2015 09:47:40 +0000
parents ef1fd8b0f3c4
children
line wrap: on
line source
import os, sys
import numpy as np
import scipy as sp
from scipy.ndimage.filters import *
from vampy import *
from copy import deepcopy

class HPspectrogram: 
	
	def __init__(self, inputSampleRate):

		# flags:
		self.vampy_flags = vf_DEBUG | vf_ARRAY | vf_REALTIME
		self.inputSampleRate = inputSampleRate
		self.stepSize = 1024
		self.blockSize = 2048
		self.channels = 1
		self.harmonic_medwin = 8 	
		self.percussive_medwin = 8 	
		self.harmonic_thresh = 0.5
		self.percussive_thresh = 0.5
		self.whitening_on = False
		self.whitenRelaxCoeff = 0.9997
		self.whitenFloor = 0.01
		self.magPeaks = None
		
	def initialise(self, channels, stepSize, blockSize):
		self.channels = channels
		self.stepSize = stepSize		
		self.blockSize = blockSize
		self.maglist = []
		self.timestamp = []
		return True
		
	def reset(self):
		# reset any initial conditions
		self.maglist = []
		self.timestamp = []
		return None
	
	def getMaker(self):
		return 'Mi Tian'
	
	def getName(self):
		return 'Harmonic percussive spectrogram'
		
	def getIdentifier(self):
		return 'hps'

	def getDescription(self):
		return 'Harmonic and percussive emphasised spectrograms.'
	
	def getCopyright(self):
		return ''

	def getMaxChannelCount(self):
		return 1
		
	def getInputDomain(self):
		return FrequencyDomain
			
	def getOutputDescriptors(self):

		#Generic values are the same for all
		Generic = OutputDescriptor()
		Generic.hasFixedBinCount=False
		Generic.hasKnownExtents=False
		Generic.isQuantized=False
		Generic.sampleType = OneSamplePerStep
		Generic.unit = 'Hz'		
		
		HSPEC = OutputDescriptor(Generic)
		HSPEC.identifier = 'gt'
		HSPEC.name = 'Harmonic emphasised spectrogram'
		HSPEC.description = 'Harmonic emphasised spectrogram'
		HSPEC.binCount = self.nBands
		
		PSPEC = OutputDescriptor(Generic)
		PSPEC.identifier = 'gt'
		PSPEC.name = 'Percussive emphasised spectrogram'
		PSPEC.description = 'Percussive emphasised spectrogram'
		
		return OutputList(HSPEC, PSPEC)

	def getParameterDescriptors(self):
		
		harmonic_thresh = ParameterDescriptor()
		harmonic_thresh.identifier='percussive_thresh'
		harmonic_thresh.name='percussive_thresh'
		harmonic_thresh.description='Binarisation threshold for harmonic emphasised magnitude spectrogram'
		harmonic_thresh.unit='v'
		harmonic_thresh.minValue=0
		harmonic_thresh.maxValue=1
		harmonic_thresh.defaultValue=0.5
		harmonic_thresh.isQuantized=False

		percussive_thresh = ParameterDescriptor(harmonic_thresh)
		percussive_thresh.identifier='percussive_thresh'
		percussive_thresh.name='percussive_thresh'
		percussive_thresh.description='Binarisation threshold for percussive emphasised magnitude spectrogram'
		
		harmonic_medwin = ParameterDescriptor()
		harmonic_medwin.identifier = 'harmonic_medwin'
		harmonic_medwin.description = 'Median window length for harmonic part.'
		harmonic_medwin.name = 'Median window length for harmonic part.'
		harmonic_medwin.minValue = 1
		harmonic_medwin.defaultValue = 8
		harmonic_medwin.maxValue = 15
		harmonic_medwin.isQuantized = True

		percussive_medwin = ParameterDescriptor(harmonic_medwin)
		percussive_medwin.identifier = 'percussive_medwin'
		percussive_medwin.description = 'Median window length for percussive part.'
		percussive_medwin.name = 'Median window length for percussive part.'
		
		boolDescriptor = ParameterDescriptor()
		boolDescriptor.isQuantized = True
		boolDescriptor.minValue= 0
		boolDescriptor.maxValue= 1
		boolDescriptor.quantizeStep = 1
		
		whitening = ParameterDescriptor(boolDescriptor) 
		whitening.identifier='whitening'
		whitening.name='Adaptive whitening'
		whitening.description='Turn adaptive whitening on or off'
		whitening.defaultValue = False
		
		return ParameterList(harmonic_thresh, percussive_thresh, harmonic_medwin, percussive_medwin, whitening)

	def setParameter(self, paramid, newval):
		if paramid == 'percussive_thresh' :
			self.percussive_thresh = newval
		if paramid == 'harmonic_medwin' :
			self.harmonic_medwin = newval
		if paramid == 'harmonic_medwin' :
			self.harmonic_medwin = newval
		if paramid == 'percussive_medwin' :
			self.percussive_medwin = newval
		if paramid == 'whitening' :
			self.whitening_on = newval == 1.0
			
		return None
		
	def getParameter(self, paramid):
		if paramid == 'percussive_thresh' :
			return self.percussive_thresh
		if paramid == 'harmonic_medwin' :
			return self.harmonic_medwin
		if paramid == 'percussive_medwin' :
			return self.percussive_medwin
		if paramid == 'harmonic_medwin' :
			return self.harmonic_medwin	
		if paramid == 'whitening' :
			if self.whitening_on :
				return 1.0
			else :
				return 0.0
		else:
			return 0.0

	def whiten(self, magnitudeSpectrogram):
		'''This function reproduces adaptive whitening as described in Dan Stowell's paper.'''
	
		half_length = self.blockSize * 0.5 + 1.0
		nFrames = magnitudeSpectrogram.shape[0]
		whitened_ms = np.zeros_like(magnitudeSpectrogram)
		
		if self.magPeaks is None :
			self.magPeaks = np.zeros(half_length, dtype = float32)
	
		for i in xrange(nFrames):
			m = magnitudeSpectrogram[i, :]	
			idx = m < self.magPeaks
			m[idx] += (self.magPeaks[idx] - m[idx]) * self.whitenRelaxCoeff
			m[m < self.whitenFloor] = self.whitenFloor
			self.magPeaks = m
		
			whitened_ms[i, :] = magnitudeSpectrogram[i, :] / m
		
		return whitened_ms
			
	def process(self, inputbuffers, timestamp):

		output_featureSet = FeatureSet()
		self.timestamp.append(timestamp)
		complexSpectrum = inputbuffers[0]		
		magnitudeSpectrum = abs(complexSpectrum) 
		self.maglist.append(magnitudeSpectrum)

		return output_featureSet
	
	def getRemainingFeatures(self):
		
		output_featureSet = FeatureSet() 
		
		nFrames = len(self.maglist)
		magnitudeSpectrogram = np.array(self.maglist)
		
		if self.whitening_on:
			magnitudeSpectrogram = self.whiten(magnitudeSpectrogram)
		else:
			magnitudeSpectrogram = (magnitudeSpectrogram - np.min(magnitudeSpectrogram)) / (np.max(magnitudeSpectrogram) - np.min(magnitudeSpectrogram))
		
		harmonic_ma = median_filter(magnitudeSpectrogram, size=(self.harmonic_medwin, 1))
		percussive_ma = median_filter(magnitudeSpectrogram, size=(1, self.percussive_medwin))
		
		harmonicSpectrogram = magnitudeSpectrogram * (harmonic_ma>=percussive_ma).astype(float)
		percussiveSpectrogram = magnitudeSpectrogram * (harmonic_ma<percussive_ma).astype(float)

		output_featureSet[0] = flist0 = FeatureList()
		output_featureSet[1] = flist1 = FeatureList()
		for frame in xrange(nFrames):
			f = Feature(timestamp = self.timestamp[frame], values = ma_harmonicSpectrogram[frame, :])
			flist0.append(f)
			f = Feature(timestamp = self.timestamp[frame], values = ma_percussiveSpectrogram[frame, :])
			flist1.append(f)
		
		return output_featureSet