def OnNewBuffer(self, buffer, sampleInterval):
		freqData = map(lambda x: absolute(x) ** 2.0, fourier(buffer))
		#freqResolution = rawSps /( constants.windowSize * sampleInterval)
		freqResolution = samplesPerSecond / windowSize
		
		lowIndex = 60/freqResolution - 1
		highIndex = 60/freqResolution + 1
		
		lowMagnitude = freqData[9] + freqData[8] + freqData[7]
		highMagnitude = freqData[11] + freqData[12] + freqData[13]
		
		if lowMagnitude < highMagnitude:
			self.dir = 1
		elif lowMagnitude > highMagnitude:
			self.dir = -1
		else:
			self.dir = 0
		
		if self.dir * self.lastDir < 0:
			self.intervalChangeSize *= 0.9
		
		sampleInterval -= self.dir * self.intervalChangeSize
		self.lastDir = self.dir
		
		return sampleInterval, sampleInterval
	def OnNewBuffer(self, buffer, sampleInterval):	
		self.t += 1
		
		power = map(lambda x: absolute(x) ** 2.0, fourier(buffer))
		bins = [9, 11]
		leakage = sum([power[bin] for bin in bins])
		
		if self.lastInterval == sampleInterval:
			#print 'passing...'
			pass
		elif leakage < self.lastLeakage:
			if leakage < self.bestLeakage:
				self.bestLeakage = leakage
				self.bestInterval = sampleInterval
			
			self.lastLeakage = leakage
			self.lastInterval = sampleInterval
			
		else:
			if self.CanMoveUphill():
				self.lastLeakage = leakage
				self.lastInterval = sampleInterval
			else:
				#print 'here'
				return self.bestInterval, self.lastInterval
		
		#make a random guess in some direction
		newInterval = self.lastInterval * (1.0 + 0.01 * (random() - 0.5)/(self.t**0.8))
		
		return self.bestInterval, newInterval
	def OnNewBuffer(self, buffer, sampleInterval):
		power = map(lambda x: absolute(x) ** 2.0, fourier(buffer))
		
		leakage = power[9] + power[11]
		
		if leakage < self.bestLeakage:
			self.bestLeakage = leakage
			self.bestInterval = sampleInterval
		
		self.xs.append(sampleInterval)
		self.ys.append(leakage)
		
		if len(self.xs) > 5:
			#fit quadratic to the leakages and sample intervals
			coefficients = polyfit(self.xs, self.ys, 2)
			nextInterval = stats.quadraticMinimum(*coefficients)
			
			self.bestInterval = nextInterval
			#print rawSps / nextInterval
			
		else:
			nextInterval = self.bestInterval * (1.0 + self.initialLeapSize*(random() - 0.5))
			
		print rawSps / nextInterval
			
		return self.bestInterval, nextInterval
	def __init__(self, sampleInterval, increment = 0.01):
		self.shapes = []
		increment = 0.01; bottom = 764.0; top = 772.0
		
		frequencies = range(0, 384+1, 6)
		
		for sps in [bottom + increment * i for i in range(int((top-bottom)/increment))]:
			timeData = [sin(60.0*2.0 * pi * t/sps) for t in range(windowSize)]
			freqData = self.normalize(map(absolute, fourier(timeData)))
			
			self.shapes.append((sps, freqData))
def ConvergeOnCoherentSampling(rawData, rawSps):
	sampleInterval = rawSps / (constants.samplesPerSecond + 5.0)
	intervalCounter = 0.0
	
	bufferOverlap = constants.windowSize / constants.transformsPerSecond
	
	buffer = []
	
	lastSample = 0.0
	dir = 0
	lastDir = 0
	intervalChangeSize = sampleInterval * 0.005
	
	for sample in rawData:
		intervalCounter += 1.0
		if intervalCounter >= sampleInterval:
			intervalCounter %= sampleInterval
			weight0 = intervalCounter
			weight1 = 1.0 - intervalCounter
			
			interpolatedSample = weight0 * sample + weight1 * lastSample
			
			buffer.append(interpolatedSample)
			
			if len(buffer) == constants.windowSize + bufferOverlap:
				buffer = buffer[bufferOverlap :]
				
				freqData = fourier(buffer)
				#freqResolution = rawSps /( constants.windowSize * sampleInterval)
				freqResolution = constants.samplesPerSecond / constants.windowSize
				
				lowIndex = 60/freqResolution - 1
				highIndex = 60/freqResolution + 1
				
				lowMagnitude = absolute(freqData[9]) + absolute(freqData[8]) + absolute(freqData[7])
				highMagnitude = absolute(freqData[11]) + absolute(freqData[12]) + absolute(freqData[13])
				
				if lowMagnitude < highMagnitude:
					dir = 1
				elif lowMagnitude > highMagnitude:
					dir = -1
				else:
					dir = 0
				
				if dir * lastDir < 0:
					intervalChangeSize *= 0.9
				
				sampleInterval -= dir * intervalChangeSize
				lastDir = dir
				
				print sampleInterval
				
		lastSample = sample
	def OnNewBuffer(self, buffer, sampleInterval):
		self.t += 1
		power = map(lambda x: absolute(x) ** 2.0, fourier(buffer))
		bins = [8, 9, 11, 12]
		leakage = sum([power[bin] for bin in bins])
		
		if leakage < self.bestLeakage:
			self.bestLeakage = leakage
			self.bestInterval = sampleInterval
			print (rawSps / self.bestInterval), self.bestLeakage
			
		newInterval = self.bestInterval * (1.0 + 0.005 * (random() - 0.5)/sqrt(self.t))
		return newInterval, self.bestInterval
	def OnNewBuffer(self, buffer, sampleInterval):
		fData = self.normalize(map(absolute, fourier(buffer)))
		
		closest = None
		for sps, data in self.shapes:
			dist = self.distance(data, fData)
			if closest is None or dist < closest[0]:
				closest = (dist, sps)
				
		newSampleInterval = sampleInterval * closest[1] / samplesPerSecond
		
		print closest, (rawSps / newSampleInterval), (rawSps / sampleInterval)
		return newSampleInterval, newSampleInterval
	def OnNewBuffer(self, buffer, sampleInterval):
		power = map(lambda x: absolute(x) ** 2.0, fourier(buffer))
		
		leakage = power[9] + power[11]
		
		if leakage < self.bestLeakage:
			self.bestLeakage = leakage
			self.bestInterval = sampleInterval
			
		left = power[8] + power[9]
		right = power[11] + power[12]
		center = (left) / (left + right) - 0.5
		#print left, right, center, rawSps / sampleInterval
		newInterval = self.bestInterval * (1.0 + self.leapSize * (random() - center) / (self.t**self.decayPow))
			
		return self.bestInterval, newInterval
	def OnNewBuffer(self, buffer, sampleInterval):
		self.t += 1
		power = map(lambda x: absolute(x) ** 2.0, fourier(buffer))
		bins = [9, 11]
		leakage = sum([power[bin] for bin in bins])
		
		if leakage < self.bestLeakage:
			self.bestLeakage = leakage
			self.bestInterval = self.lastInterval
			
		#self.lastInterval = self.bestInterval * (1.0 + self.leapSize * (random() - 0.5)/(self.t**self.decayPow))
		#maxLeapSize = self.leapSize / log10(self.t)
		maxLeapSize = self.leapSize / (self.t**self.decayPow)
		
		self.lastInterval = self.bestInterval * (1.0 + maxLeapSize * (random() - 0.5))
		
		return self.bestInterval, self.lastInterval
def getToneLeakage(downSampledData, binningType = 1):
	fData = map(lambda x: x*x, map(absolute, fourier(downSampledData)))
	#pylab.semilogy(frequencies, fData); pylab.show()
	
	#leakage = sum([x for x, f in zip(fData, frequencies) if abs(f % 60.0) > 5.0])
	#bins = constants.bins
	
	#bins = [9, 11]	
	#leakage = sum([fData[x] for x in constants.bins])
	
	if binningType == 0:
		leakage = sum([fData[i] for i in range(len(fData)) if i != 10]) / fData[10]
	elif binningType == 1:
		leakage = (fData[9] + fData[11]) / fData[10]
	elif binningType == 2:
		leakage = fData[9] /fData[10]
	elif binningType == 3:
		leakage = fData[11] / fData[10]
	
	return leakage
	def OnNewBuffer(self, buffer, sampleInterval):
		self.t += 1
		power = map(lambda x: absolute(x) ** 2.0, fourier(buffer))
		bins = [9, 11]
		leakage = sum([power[bin] for bin in bins])
		
		if leakage > self.lastLeakage and not self.__CanMoveUphill():
			return self.lastInterval, self.bestInterval
		
		if leakage < self.bestLeakage:
			self.bestLeakage = leakage
			self.bestInterval = self.lastInterval
			
		#move in a random direction by a scaled random amount
		x = 20.0
		movement = (random() - 0.5) * self.intervalChangeSize * x / (self.t + x) 
		
		self.lastLeakage = leakage
		self.lastInterval = sampleInterval
		
		return (sampleInterval + movement), self.bestInterval
def getToneLeakage(downSampledData):
	noiseBin = 10
	power = map(lambda x: x*x, map(numpy.absolute, fourier(downSampledData)))
	result = (power[noiseBin-1] + power[noiseBin+1]) / power[noiseBin]
	#result = power[noiseBin-1] + power[noiseBin+1]
	return result