def setUp(self): self.x = Audio(fs=10, initialdata=np.zeros((10, 1))) self.x.samples[0] = -1.0 self.x.samples[1] = 1.0 print(self.x) print(self.x.samples) print()
def __init__(self, N=None, taps=None, fs=96000, repeats=2, B=(1, 0, 0), A=(1, 0, 0)): """N is the order of the MLS, taps are preferably selected from the mlstaps dictionary, like >>> taps=TAPS[N][0] B and A are emphasis filter coefficients. The filter used as emphasis must be a minimum phase filter. This means that all the poles and the zeroes are withing the unit circle. We can then invert the filter to apply de-emphasis. The filters.biquads.RBJ class can be used to generate a suitable emphasis filter. """ assert repeats > 1, "at least two sequences are needed, (repeats=2)" _MLS_base.__init__(self, N=N, taps=taps) Audio.__init__(self, fs=fs, initialdata=self.get_full_sequence(repeats=repeats)) self.repeats = repeats self._length_impresp = self.L / self.fs self._filter_emphasis = Filter(B=B, A=A, fs=self.fs) self._filter_deemphasis = Filter(B=A, A=B, fs=self.fs) # inverse filter assert self._filter_emphasis.is_minimum_phase(), \ "The emphasis filter must be minimum phase, i.e. possible to invert"
def __init__(self, N=None, taps=None, fs=96000, repeats=2, B=(1, 0, 0), A=(1, 0, 0)): """N is the order of the MLS, taps are preferably selected from the mlstaps dictionary, like >>> taps=TAPS[N][0] B and A are emphasis filter coefficients. The filter used as emphasis must be a minimum phase filter. This means that all the poles and the zeroes are withing the unit circle. We can then invert the filter to apply de-emphasis. The filters.biquads.RBJ class can be used to generate a suitable emphasis filter. """ assert repeats > 1, "at least two sequences are needed, (repeats=2)" _MLS_base.__init__(self, N=N, taps=taps) Audio.__init__(self, fs=fs, initialdata=self.get_full_sequence(repeats=repeats)) self.repeats = repeats self._length_impresp = self.L/self.fs self._filter_emphasis = Filter(B=B, A=A, fs=self.fs) self._filter_deemphasis = Filter(B=A, A=B, fs=self.fs) # inverse filter assert self._filter_emphasis.is_minimum_phase(), \ "The emphasis filter must be minimum phase, i.e. possible to invert"
def test_int8(self): x = Audio(fs=10, initialdata=np.zeros((10, 1), dtype=np.int8)) x.samples[0] = -128 x.samples[1] = 127 self.convert(x, targetbits=32) self.assertAlmostEqual(x.samples[0], -1.0, places=20) self.assertAlmostEqual(x.samples[1], 127/128, places=20)
def test_int16(self): x = Audio(fs=10, initialdata=np.zeros((10, 1), dtype=np.int16)) x.samples[0] = -32768 x.samples[1] = 32767 self.convert(x, targetbits=32) self.assertAlmostEqual(x.samples[0], -1.0, places=20) self.assertAlmostEqual(x.samples[1], 32767/32768, places=20)
def test_int32(self): x = Audio(fs=10, initialdata=np.zeros((10, 1), dtype=np.int32)) x.samples[0] = -2147483648 x.samples[1] = 2147483647 self.convert(x, targetbits=32) # resolution is lost in this conversion, however we should be close enough. self.assertAlmostEqual(x.samples[0], -1.0, places=20) # exact value self.assertAlmostEqual(x.samples[1], 1.0, places=20) # close enough
def play(self, x, frames_per_buffer=1024): """Play audio. If dropouts or buffer underruns occur try different values for the frames_per_buffer variable.""" _Device.play(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 stream = self.pa.open(format = self._data_format(x), channels = x.ch, rate = x.fs, frames_per_buffer = frames_per_buffer, output_device_index = self._index_out, input = False, output = True, ) try: self._logger.info("play: 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 = iter(np.split(cpy.samples, len(cpy)/frames_per_buffer)) try: while True: chunk = it.next() stream.write(chunk.tostring(), num_frames=frames_per_buffer) 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: close stream") stream.close() self._logger.info("play: done")
def check_values(self, values, expected, position): x = Audio(fs=10, initialdata=values) peak, idx = x.peak() self.assertTrue(len(peak)==1) self.assertTrue(len(idx)==1) print("index: %3i peak: %f" %(idx, peak)) print(x) self.assertAlmostEqual(peak, expected, places=3) self.assertEqual(idx, position)
def check_values(self, values, expected, position): x = Audio(fs=10, initialdata=values) peak, idx = x.peak() self.assertTrue(len(peak)==2) self.assertTrue(len(idx)==2) print("index: %s peak: %s" %(idx, peak)) print(x) self.assertAlmostEqual(peak[0], expected[0], places=3) self.assertAlmostEqual(peak[1], expected[1], places=3) self.assertEqual(idx[0], position[0]) self.assertEqual(idx[1], position[1])
class Test_ConvertFloatToInt(unittest.TestCase): def setUp(self): self.x = Audio(fs=10, initialdata=np.zeros((10, 1))) self.x.samples[0] = -1.0 self.x.samples[1] = 1.0 print(self.x) print(self.x.samples) print() def convert(self, targetbits=None): self.x.convert_to_integer(targetbits=targetbits) print(self.x) print(self.x.samples) self.assertIsInstance(self.x.samples, np.ndarray) def test_int8(self): self.convert(targetbits=8) self.assertTrue(self.x.samples.dtype==np.int8) # 8 bits 2's complement # min is -128 # max is 127 self.assertEquals(self.x.samples[0], -127) # must be symmetrical self.assertEquals(self.x.samples[1], 127) # must be symmetrical def test_int16(self): self.convert(targetbits=16) self.assertTrue(self.x.samples.dtype==np.int16) # 16 bits 2's complement # min is -32768 # max is 32767 self.assertEquals(self.x.samples[0], -32767) # must be symmetrical self.assertEquals(self.x.samples[1], 32767) # must be symmetrical def test_int32(self): self.convert(targetbits=32) self.assertTrue(self.x.samples.dtype==np.int32) # 32 bits 2's complement # min is -2147483648 # max is 2147483647 self.assertEquals(self.x.samples[0], -2147483647) # must be symmetrical self.assertEquals(self.x.samples[1], 2147483647) # must be symmetrical
def play_rec(self, x, **kwargs): _Device.play_rec(self, x, **kwargs) self._logger.warn("*** Stub play_rec") # fake a signal with white noise n = Noise(channels=x.ch, fs=x.fs, nofsamples=x.nofsamples, gaindb=-60) n.convert_to_float(targetbits=32) y = Audio(fs=x.fs, initialdata=n.samples) return y
def rec(self, duration=None, channels=1, fs=96000, **kwargs): _Device.rec(self, duration=duration, channels=channels, fs=fs, **kwargs) self._logger.warn("*** Stub rec") # fake a signal with white noise n = Noise(channels=channels, fs=fs, duration=duration, gaindb=-60) n.convert_to_float(targetbits=32) y = Audio(fs=fs, initialdata=n.samples) return y
class Test_ConstructorChannels(unittest.TestCase): def setUp(self): self.x = Audio(channels=4) print(self.x) def test_str_method(self): self.assertIsInstance(self.x.__str__(), str) def test_channels(self): self.assertEqual(self.x.ch, 4) self.assertEqual(len(self.x), 0) def test_RMS_is_nan(self): print(self.x.rms()) self.assertTrue(np.isnan(self.x.rms()).all()) def test_peak_is_nan(self): peak, idx = self.x.peak() print(peak) print(idx) self.assertTrue(np.isnan(peak).all()) self.assertTrue((idx == 0).all()) def test_crestfactor_is_nan(self): print(self.x.crest_factor()) self.assertTrue(np.isnan(self.x.crest_factor()).all())
class Test_EmptyConstructor(unittest.TestCase): def setUp(self): self.x = Audio() print(self.x) def test_default_constructor(self): self.assertAlmostEqual(self.x.fs, 96000, places=7) self.assertEqual(self.x.ch, 0) self.assertEqual(self.x.nofsamples, 0) self.assertEqual(self.x.duration, 0) self.assertIsInstance(self.x.samples, np.ndarray) def test_str_method(self): self.assertIsInstance(self.x.__str__(), str) def test_empty_comment(self): self.assertSequenceEqual(self.x.comment(), '') def test_add_comment(self): self.assertSequenceEqual(self.x.comment(), '') s = 'This is a comment\nwith a line break' self.x.comment(comment=s) print(self.x) self.assertSequenceEqual(self.x.comment(), s)
def __str__(self): B, A = self._filter_emphasis.get_coefficients() mls_string = _MLS_base.__str__(self) mls_string = "\n".join(mls_string.splitlines()[2:-1]) s = Audio.__str__(self) s += '%s\n' %mls_string s += 'repeats : %i\n' %self.repeats s += 'len(impulse) : %.3f [s]\n' %self._length_impresp s += 'emphasis filt. B : %s\n' %str(B) s += 'emphasis filt. A : %s\n' %str(A) return s
def __str__(self): B, A = self._filter_emphasis.get_coefficients() mls_string = _MLS_base.__str__(self) mls_string = "\n".join(mls_string.splitlines()[2:-1]) s = Audio.__str__(self) s += '%s\n' % mls_string s += 'repeats : %i\n' % self.repeats s += 'len(impulse) : %.3f [s]\n' % self._length_impresp s += 'emphasis filt. B : %s\n' % str(B) s += 'emphasis filt. A : %s\n' % str(A) return s
def test_set_samples(self): x = Audio(nofsamples=300, fs=600) print(x) self.assertAlmostEqual(x.duration, 0.5, places=7)
def setUp(self): self.x = Audio(channels=4) print(self.x)
def setUp(self): self.x = Audio() print(self.x)
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 test_set_duration(self): x = Audio(duration=1.5, fs=600) print(x) self.assertEqual(len(x), 900)
class Test_ConvertBackToBack(unittest.TestCase): def setUp(self): self.x = Audio(fs=10, initialdata=np.zeros((10, 1))) self.x.samples[0] = -1.0 self.x.samples[1] = 1.0 print(self.x) print(self.x.samples) print() def quantization_step_size(self, bits): return 2**-(bits-1) def test_float_to_int8_to_float64(self): self.x.convert_to_integer(targetbits=8) self.x.convert_to_float(targetbits=64) print(self.x) print(self.x.samples) q = self.quantization_step_size(8) self.assertAlmostEqual(self.x.samples[0], -1.0 + q, places=20) self.assertAlmostEqual(self.x.samples[1], 1.0 - q, places=20) def test_float_to_int16_to_float64(self): self.x.convert_to_integer(targetbits=16) self.x.convert_to_float(targetbits=64) print(self.x) print(self.x.samples) q = self.quantization_step_size(16) self.assertAlmostEqual(self.x.samples[0], -1.0 + q, places=20) self.assertAlmostEqual(self.x.samples[1], 1.0 - q, places=20) def test_float_to_int32_to_float64(self): self.x.convert_to_integer(targetbits=32) self.x.convert_to_float(targetbits=64) print(self.x) print(self.x.samples) q = self.quantization_step_size(32) self.assertAlmostEqual(self.x.samples[0], -1.0 + q, places=20) self.assertAlmostEqual(self.x.samples[1], 1.0 - q, places=20)
def get_impulse(self, x): """Extract the impulse response. Returns an Audio instance. """ imp = _MLS_base.get_impulse(self, x) y = Audio(fs=self.fs, initialdata=imp) return y
def test_set_duration_and_channels(self): x = Audio(duration=1.5, fs=600, channels=5) print(x) self.assertEqual(len(x), 900)
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