Exemplo n.º 1
0
class Meter(object):

	class StopException(Exception):
		pass

	def __init__(self, segment_length=None):
		"""
		:param float segment_length: A float representing `AUDIO_SEGMENT_LENGTH`
		"""
		print("__init__")
		global _soundmeter
		_soundmeter = self  # Register this object globally for use in signal handlers (see below)
		self.output = BytesIO()
		self.audio = pyaudio.PyAudio()
		self.stream = self.audio.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=FRAMES_PER_BUFFER)
		self.segment_length = segment_length
		self.is_running = False
		self._graceful = False  # Graceful stop switch
		self._data = {}
		self.acc = Accumulator(-100,0)
		self.points = 0

	def record(self):
		"""
		Record PyAudio stream into StringIO output
		This generator keeps stream open; the stream is closed in stop()
		"""
		while True:
			frames = []
			self.stream.start_stream()
			for i in range(self.num_frames):
				data = self.stream.read(FRAMES_PER_BUFFER)
				frames.append(data)
			self.output.seek(0)
			w = wave.open(self.output, 'wb')
			w.setnchannels(CHANNELS)
			w.setsampwidth(self.audio.get_sample_size(FORMAT))
			w.setframerate(RATE)
			w.writeframes(b''.join(frames))
			w.close()
			yield

	def start(self):
		segment = self.segment_length or AUDIO_SEGMENT_LENGTH
		self.num_frames = int(RATE / FRAMES_PER_BUFFER * segment)
		try:
			self.is_running = True
			record = self.record()
			while not self._graceful:
				next(record)  # Record stream `AUDIO_SEGMENT_LENGTH' long in the generator method 'record'
				data = self.output.getvalue()
				segment = pydub.AudioSegment(data)
				rms = segment.rms
				dbfs = segment.dBFS
				self.meter(rms, dbfs)
			self.is_running = False
			self.stop()

		except self.__class__.StopException:
			self.is_running = False
			self.stop()

	def meter(self, rms, dbfs):
		if not self._graceful:
			if self.acc.n < ACCUMULATE:
				self.acc.addValue(dbfs)
			else:
				if self.acc.mean() < -40:
					self.points = self.points + 1
					moteflash()
				sys.stdout.write("\nAccumulation: min{:+8.3f}\tmax{:+8.3f}\tmean{:+8.3f}\tpoints{:4d}\n".format(self.acc.min_value, self.acc.max_value, self.acc.mean(), self.points))
				self.acc = Accumulator(-100,0) # reset accumulator
			mm = 128 + dbfs # motemeter value
			sys.stdout.write("\r{:+08.3f}\t{:+08.3f}".format(dbfs,mm))
			sys.stdout.flush()
			motemeter(mm)
			
	def graceful(self):
		"""Graceful stop so that the while loop in start() will stop after the
		 current recording cycle"""
		self._graceful = True

	def stop(self):
		"""Stop the stream and terminate PyAudio"""
		if not self._graceful:
			self._graceful = True
		self.stream.stop_stream()
		self.audio.terminate()
		sys.stdout.write("\nPoints={0}\n".format(self.points))
		mote.clear()
		mote.show()