def rec(self, duration=None, channels=1, fs=96000, frames_per_buffer=1024, dtype=np.float32): """Record. If dropouts or buffer underruns occur try different values for the frames_per_buffer variable.""" _Device.rec(self, duration=duration, channels=channels, fs=fs) self._validate(frames_per_buffer) missing_frames = self._get_missing_frames(frames_per_buffer, int(duration*fs)) nofsamples = missing_frames+int(duration*fs) rec = Audio(channels=channels, fs=fs, nofsamples=nofsamples, dtype=dtype) assert len(rec)%frames_per_buffer == 0 stream = self.pa.open(format = self._data_format(rec), channels = rec.ch, rate = rec.fs, frames_per_buffer = frames_per_buffer, input_device_index = self._index_in, input = True, output = False, ) try: self._logger.info("rec: start") counter = 0 # split the audio into chunks the size of one buffer, so we can # iterate over the audio in chunksizes of the same size as one buffer it_in = iter(np.split(rec.samples, len(rec)/frames_per_buffer)) try: while True: chunk_in = it_in.next() raw_1d = np.fromstring(stream.read(frames_per_buffer), dtype=rec.samples.dtype) # because we use an iterator chunk_in is a sliding window in the rec variable chunk_in[:] = raw_1d.reshape((frames_per_buffer, rec.ch)) counter += 1 except StopIteration: pass finally: stream.stop_stream() self._logger.debug("chunks recorded : %i" %counter) self._logger.debug("samples recorded: %i" %(counter*frames_per_buffer)) self._logger.debug("duration : %.3f" %(counter*frames_per_buffer/rec.fs)) finally: self._logger.debug("rec: close stream") stream.close() # remove the padding (empty frames) added to fill the last buffer. Trim # at the start, since we can treat that as latency. rec.trim(start=missing_frames, end=None) self._logger.debug("rec: trimmed %i samples from the start" %missing_frames) self._check_if_clipped(rec) self._logger.info("rec: done") return rec
def play_rec(self, x, frames_per_buffer=1024): """Play audio and record from input. If dropouts or buffer underruns occur try different values for the frames_per_buffer variable.""" _Device.play_rec(self, x) self._validate(frames_per_buffer) missing_frames = self._get_missing_frames(frames_per_buffer, len(x)) # generate silence to fill up missing frames pad = Audio(channels=x.ch, fs=x.fs, nofsamples=missing_frames, dtype=x.samples.dtype) # append the missing frames to a copy of the audio to be played. We now have # audio that can be split into complete (full) buffers cpy = Audio(fs=x.fs, initialdata=x.samples) cpy.concat(pad) assert len(cpy)%frames_per_buffer == 0 rec = Audio(channels=cpy.ch, fs=cpy.fs, nofsamples=len(cpy), dtype=cpy.samples.dtype) stream = self.pa.open(format = self._data_format(x), channels = x.ch, rate = x.fs, frames_per_buffer = frames_per_buffer, input_device_index = self._index_in, output_device_index = self._index_out, input = True, output = True, ) try: self._logger.info("play_rec: start") counter = 0 # split the audio into chunks the size of one buffer, so we can # iterate over the audio in chunksizes of the same size as one buffer it_out = iter(np.split(cpy.samples, len(cpy)/frames_per_buffer)) it_in = iter(np.split(rec.samples, len(rec)/frames_per_buffer)) try: while True: chunk_out = it_out.next() chunk_in = it_in.next() stream.write(chunk_out.tostring(), num_frames=frames_per_buffer) raw_1d = np.fromstring(stream.read(frames_per_buffer), dtype=rec.samples.dtype) # because we use an iterator chunk_in is a sliding window in the rec variable chunk_in[:] = raw_1d.reshape((frames_per_buffer, rec.ch)) counter += 1 except StopIteration: pass finally: stream.stop_stream() self._logger.debug("chunks played : %i" %counter) self._logger.debug("samples played : %i" %(counter*frames_per_buffer)) self._logger.debug("duration : %.3f" %(counter*frames_per_buffer/x.fs)) finally: self._logger.debug("play_rec: close stream") stream.close() # remove the padding (empty frames) added to fill the last buffer. Trim # at the start, since we can treat that as latency. rec.trim(start=missing_frames, end=None) self._logger.debug("play_rec: trimmed %i samples from the start" %missing_frames) self._check_if_clipped(rec) self._logger.info("play_rec: done") return rec