From 46f3729f9b08c04a5872e438396db3206acdf0c3 Mon Sep 17 00:00:00 2001 From: Peter Conerly Date: Thu, 23 Aug 2018 01:22:49 -0700 Subject: [PATCH 1/5] Add seeking to rawread and macca, and tests --- .gitignore | 3 + audioread/__init__.py | 12 +-- audioread/macca.py | 14 ++- audioread/rawread.py | 15 +++- test.py | 10 +++ test/fixtures/README.md | 19 ++++ test/fixtures/make_test_wave.py | 40 +++++++++ test/fixtures/test.wav | Bin 0 -> 16442 bytes test/fixtures/wavetest.wave | Bin 0 -> 16428 bytes test/fixtures/wavetest2.wave | Bin 0 -> 4140 bytes test/test_audioread.py | 153 ++++++++++++++++++++++++++++++++ tox.ini | 6 ++ 12 files changed, 261 insertions(+), 11 deletions(-) create mode 100644 .gitignore create mode 100644 test.py create mode 100644 test/fixtures/README.md create mode 100644 test/fixtures/make_test_wave.py create mode 100644 test/fixtures/test.wav create mode 100644 test/fixtures/wavetest.wave create mode 100644 test/fixtures/wavetest2.wave create mode 100644 test/test_audioread.py create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e4a0c7b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pyc + +.tox/ diff --git a/audioread/__init__.py b/audioread/__init__.py index 740bc55..93ef684 100644 --- a/audioread/__init__.py +++ b/audioread/__init__.py @@ -70,14 +70,14 @@ def _mad_available(): return True -def audio_open(path): +def audio_open(path, block_samples=4096): """Open an audio file using a library that is available on this system. """ # Standard-library WAV and AIFF readers. from . import rawread try: - return rawread.RawAudioFile(path) + return rawread.RawAudioFile(path, block_samples=block_samples) except DecodeError: pass @@ -85,7 +85,7 @@ def audio_open(path): if _ca_available(): from . import macca try: - return macca.ExtAudioFile(path) + return macca.ExtAudioFile(path, block_samples=block_samples) except DecodeError: pass @@ -93,7 +93,7 @@ def audio_open(path): if _gst_available(): from . import gstdec try: - return gstdec.GstAudioFile(path) + return gstdec.GstAudioFile(path, block_samples=block_samples) except DecodeError: pass @@ -101,14 +101,14 @@ def audio_open(path): if _mad_available(): from . import maddec try: - return maddec.MadAudioFile(path) + return maddec.MadAudioFile(path, block_samples=block_samples) except DecodeError: pass # FFmpeg. from . import ffdec try: - return ffdec.FFmpegAudioFile(path) + return ffdec.FFmpegAudioFile(path, block_samples=block_samples) except DecodeError: pass diff --git a/audioread/macca.py b/audioread/macca.py index e1903c0..797d396 100644 --- a/audioread/macca.py +++ b/audioread/macca.py @@ -195,7 +195,8 @@ class ExtAudioFile(object): >>> do_something(block) """ - def __init__(self, filename): + block_samples = None + def __init__(self, filename, block_samples=4096): url = CFURL(filename) try: self._obj = self._open_url(url) @@ -204,6 +205,7 @@ def __init__(self, filename): raise del url + self.block_samples = block_samples self.closed = False self._file_fmt = None self._client_fmt = None @@ -295,9 +297,12 @@ def setup(self, bitdepth=16): newfmt.mBytesPerFrame = newfmt.mBytesPerPacket self.set_client_format(newfmt) - def read_data(self, blocksize=4096): + def read_data(self, blocksize=None): """Generates byte strings reflecting the audio data in the file. """ + if blocksize is None: + blocksize = self.block_samples * self._client_fmt.mBytesPerFrame + frames = ctypes.c_uint(blocksize // self._client_fmt.mBytesPerFrame) buf = ctypes.create_string_buffer(blocksize) @@ -323,6 +328,11 @@ def read_data(self, blocksize=4096): blob = data[:size] yield blob + def seek(self, pos): + """Seeks to the position in the file""" + check(_coreaudio.ExtAudioFileSeek(self._obj, pos)) + + def close(self): """Close the audio file and free associated memory.""" if not self.closed: diff --git a/audioread/rawread.py b/audioread/rawread.py index 2ff476a..96fcd66 100644 --- a/audioread/rawread.py +++ b/audioread/rawread.py @@ -57,8 +57,10 @@ class RawAudioFile(object): """An AIFF, WAV, or Au file that can be read by the Python standard library modules ``wave``, ``aifc``, and ``sunau``. """ - def __init__(self, filename): + block_samples = None + def __init__(self, filename, block_samples=1024): self._fh = open(filename, 'rb') + self.block_samples = block_samples try: self._file = aifc.open(self._fh) @@ -71,7 +73,7 @@ def __init__(self, filename): return try: - self._file = wave.open(self._fh) + self._file = wave.open(self._fh, 'r') except wave.Error: self._fh.seek(0) pass @@ -107,6 +109,11 @@ def close(self): self._file.close() self._fh.close() + def seek(self, pos): + """Seek to the position in the file""" + # All three libraries have the same method for seeking + self._file.setpos(pos) + @property def channels(self): """Number of audio channels.""" @@ -122,7 +129,9 @@ def duration(self): """Length of the audio in seconds (a float).""" return float(self._file.getnframes()) / self.samplerate - def read_data(self, block_samples=1024): + def read_data(self, block_samples=None): + if block_samples is None: + block_samples = self.block_samples """Generates blocks of PCM data found in the file.""" old_width = self._file.getsampwidth() diff --git a/test.py b/test.py new file mode 100644 index 0000000..35fa6de --- /dev/null +++ b/test.py @@ -0,0 +1,10 @@ +import unittest +import sys + +if __name__ == '__main__': + loader = unittest.TestLoader() + tests = loader.discover('test') + testRunner = unittest.runner.TextTestRunner() + result = testRunner.run(tests) + if not result.wasSuccessful(): + sys.exit(1) \ No newline at end of file diff --git a/test/fixtures/README.md b/test/fixtures/README.md new file mode 100644 index 0000000..e4653b3 --- /dev/null +++ b/test/fixtures/README.md @@ -0,0 +1,19 @@ +Audio file fixtures for the tests. + +#### test.wav +Test.wav was produced by doing: + +```py +import numpy as np +from scipy.io import wavfile + +if __name__ == '__main__': + size = 512 + a = np.full((size, ), 0.) + b = np.full((size, ), 0.2) + c = np.full((size, ), 0.5) + d = np.full((size, ), 0.9) + t = np.concatenate((a, b, c, d)) + + wavfile.write('test.wav', 44100, t) +``` diff --git a/test/fixtures/make_test_wave.py b/test/fixtures/make_test_wave.py new file mode 100644 index 0000000..c3e3739 --- /dev/null +++ b/test/fixtures/make_test_wave.py @@ -0,0 +1,40 @@ +import numpy as np +import wave +import struct + +def getData(): + # size = 512 / 8 + size = 512 + # a = np.full((size, ), 0.) + # b = np.full((size, ), 200.) + # c = np.full((size, ), 500.) + # d = np.full((size, ), 900.) + + a = np.full((size, ), 0., dtype=np.float16) + b = np.full((size, ), 0.2, dtype=np.float16) + c = np.full((size, ), 0.5, dtype=np.float16) + d = np.full((size, ), 0.9, dtype=np.float16) + t = np.concatenate((a, b, c, d)) + return t + +def getItemBytes(x): + # return x.tobytes() + ba = bytearray(struct.pack("f", x)) + return ba + + +if __name__ == '__main__': + fout = wave.open('test/fixtures/wavetest2.wave', 'w') + data = getData() + fout.setnchannels(1) + fout.setframerate(44100) + fout.setsampwidth(2) + + fout.writeframes(data.tobytes()) + + # data = np.filter() + # v = np.vectorize(getItemBytes) + # out = v(data) + # fout.writeframes(out) + + fout.close() diff --git a/test/fixtures/test.wav b/test/fixtures/test.wav new file mode 100644 index 0000000000000000000000000000000000000000..a8b5271dac3a2b8f31a662e193f825733a76187b GIT binary patch literal 16442 zcmeI$u?fOJ6oBC;Dp)%~W^jR1(15Ll)~AxrF3ac)E+Xg-4&V^xbc^G==8>fPdG{6B zZQFLSj5w_Jo9@y#^N1M7DAxCg<~WU63?HM*r+zZb;W5s+&%c-D*-=0N1r$&~0R%bRiL~iB) literal 0 HcmV?d00001 diff --git a/test/fixtures/wavetest.wave b/test/fixtures/wavetest.wave new file mode 100644 index 0000000000000000000000000000000000000000..32345ce1f005ad2851a1808ab165bd477619365d GIT binary patch literal 16428 zcmeI$u?fOJ7>405R+bsT!aahZ0b2{T4TzmxhHwR)!9@h!!2uk?9By$ue~N2Tz5MqS zx7+spa-JMk`_1_>F4`o`^sOJs_1I*VHm6}6GW}x|P(T3%6i`3`1r$&~0RUH4%!tv>xrGO6hz#g~<9N+*4IKTl8aDW3G k;6R-YykBL$ol^&U;2v;*103K02ROh14sd`29H`fUALVXr-T(jq literal 0 HcmV?d00001 diff --git a/test/fixtures/wavetest2.wave b/test/fixtures/wavetest2.wave new file mode 100644 index 0000000000000000000000000000000000000000..5d29340a50cee5e234f5c8368f08e7eb51c7621f GIT binary patch literal 4140 zcmWIYbaPV?U| Date: Thu, 23 Aug 2018 01:26:52 -0700 Subject: [PATCH 2/5] Cleanup --- test/fixtures/README.md | 4 ++++ test/fixtures/make_test_wave.py | 22 ++-------------------- test/fixtures/wavetest.wave | Bin 16428 -> 4140 bytes test/fixtures/wavetest2.wave | Bin 4140 -> 0 bytes test/test_audioread.py | 3 +-- 5 files changed, 7 insertions(+), 22 deletions(-) delete mode 100644 test/fixtures/wavetest2.wave diff --git a/test/fixtures/README.md b/test/fixtures/README.md index e4653b3..c248300 100644 --- a/test/fixtures/README.md +++ b/test/fixtures/README.md @@ -17,3 +17,7 @@ if __name__ == '__main__': wavfile.write('test.wav', 44100, t) ``` + +#### wavetest.wav + +Produced with `make_test_wave.py` diff --git a/test/fixtures/make_test_wave.py b/test/fixtures/make_test_wave.py index c3e3739..729dd20 100644 --- a/test/fixtures/make_test_wave.py +++ b/test/fixtures/make_test_wave.py @@ -3,38 +3,20 @@ import struct def getData(): - # size = 512 / 8 size = 512 - # a = np.full((size, ), 0.) - # b = np.full((size, ), 200.) - # c = np.full((size, ), 500.) - # d = np.full((size, ), 900.) a = np.full((size, ), 0., dtype=np.float16) b = np.full((size, ), 0.2, dtype=np.float16) c = np.full((size, ), 0.5, dtype=np.float16) d = np.full((size, ), 0.9, dtype=np.float16) - t = np.concatenate((a, b, c, d)) - return t - -def getItemBytes(x): - # return x.tobytes() - ba = bytearray(struct.pack("f", x)) - return ba + return np.concatenate((a, b, c, d)) if __name__ == '__main__': - fout = wave.open('test/fixtures/wavetest2.wave', 'w') + fout = wave.open('test/fixtures/wavetest.wave', 'w') data = getData() fout.setnchannels(1) fout.setframerate(44100) fout.setsampwidth(2) - fout.writeframes(data.tobytes()) - - # data = np.filter() - # v = np.vectorize(getItemBytes) - # out = v(data) - # fout.writeframes(out) - fout.close() diff --git a/test/fixtures/wavetest.wave b/test/fixtures/wavetest.wave index 32345ce1f005ad2851a1808ab165bd477619365d..5d29340a50cee5e234f5c8368f08e7eb51c7621f 100644 GIT binary patch literal 4140 zcmWIYbaPV?U|405R+bsT!aahZ0b2{T4TzmxhHwR)!9@h!!2uk?9By$ue~N2Tz5MqS zx7+spa-JMk`_1_>F4`o`^sOJs_1I*VHm6}6GW}x|P(T3%6i`3`1r$&~0RUH4%!tv>xrGO6hz#g~<9N+*4IKTl8aDW3G k;6R-YykBL$ol^&U;2v;*103K02ROh14sd`29H`fUALVXr-T(jq diff --git a/test/fixtures/wavetest2.wave b/test/fixtures/wavetest2.wave deleted file mode 100644 index 5d29340a50cee5e234f5c8368f08e7eb51c7621f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4140 zcmWIYbaPV?U| Date: Fri, 24 Aug 2018 10:11:33 -0700 Subject: [PATCH 3/5] Refactor tests --- .gitignore | 1 + audioread/ffdec.py | 6 +- audioread/macca.py | 6 +- audioread/maddec.py | 8 +- audioread/rawread.py | 11 +- test/fixtures/make_test_wave.py | 2 +- test/fixtures/mp3test.mp3 | Bin 0 -> 2551 bytes test/fixtures/{wavetest.wave => wavetest.wav} | Bin test/test_audioread.py | 121 +++++------------- test/test_ffdec.py | 72 +++++++++++ test/test_gstdec.py | 70 ++++++++++ test/test_macca.py | 62 +++++++++ test/test_maddec.py | 69 ++++++++++ test/test_rawread.py | 60 +++++++++ 14 files changed, 383 insertions(+), 105 deletions(-) create mode 100644 test/fixtures/mp3test.mp3 rename test/fixtures/{wavetest.wave => wavetest.wav} (100%) create mode 100644 test/test_ffdec.py create mode 100644 test/test_gstdec.py create mode 100644 test/test_macca.py create mode 100644 test/test_maddec.py create mode 100644 test/test_rawread.py diff --git a/.gitignore b/.gitignore index e4a0c7b..1a2c44f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.pyc +.DS_Store .tox/ diff --git a/audioread/ffdec.py b/audioread/ffdec.py index 8306267..c207af7 100644 --- a/audioread/ffdec.py +++ b/audioread/ffdec.py @@ -100,7 +100,7 @@ def popen_multiple(commands, command_args, *args, **kwargs): class FFmpegAudioFile(object): """An audio file decoded by the ffmpeg command-line utility.""" - def __init__(self, filename, block_size=4096): + def __init__(self, filename, block_samples=4096): # On Windows, we need to disable the subprocess's crash dialog # in case it dies. Passing SEM_NOGPFAULTERRORBOX to SetErrorMode # disables this behavior. @@ -143,7 +143,7 @@ def __init__(self, filename, block_size=4096): # Start another thread to consume the standard output of the # process, which contains raw audio data. - self.stdout_reader = QueueReaderThread(self.proc.stdout, block_size) + self.stdout_reader = QueueReaderThread(self.proc.stdout, blocksize=block_samples) self.stdout_reader.start() # Read relevant information from stderr. @@ -152,7 +152,7 @@ def __init__(self, filename, block_size=4096): # Start a separate thread to read the rest of the data from # stderr. This (a) avoids filling up the OS buffer and (b) # collects the error output for diagnosis. - self.stderr_reader = QueueReaderThread(self.proc.stderr) + self.stderr_reader = QueueReaderThread(self.proc.stderr, blocksize=block_samples) self.stderr_reader.start() def read_data(self, timeout=10.0): diff --git a/audioread/macca.py b/audioread/macca.py index 797d396..01b5897 100644 --- a/audioread/macca.py +++ b/audioread/macca.py @@ -195,7 +195,6 @@ class ExtAudioFile(object): >>> do_something(block) """ - block_samples = None def __init__(self, filename, block_samples=4096): url = CFURL(filename) try: @@ -300,8 +299,7 @@ def setup(self, bitdepth=16): def read_data(self, blocksize=None): """Generates byte strings reflecting the audio data in the file. """ - if blocksize is None: - blocksize = self.block_samples * self._client_fmt.mBytesPerFrame + blocksize = blocksize or self.block_samples * self._client_fmt.mBytesPerFrame frames = ctypes.c_uint(blocksize // self._client_fmt.mBytesPerFrame) buf = ctypes.create_string_buffer(blocksize) @@ -329,7 +327,7 @@ def read_data(self, blocksize=None): yield blob def seek(self, pos): - """Seeks to the position in the file""" + """Seek to a frame position in the file.""" check(_coreaudio.ExtAudioFileSeek(self._obj, pos)) diff --git a/audioread/maddec.py b/audioread/maddec.py index 8dd7aaa..9d3c058 100644 --- a/audioread/maddec.py +++ b/audioread/maddec.py @@ -23,7 +23,8 @@ class UnsupportedError(DecodeError): class MadAudioFile(object): """MPEG audio file decoder using the MAD library.""" - def __init__(self, filename): + def __init__(self, filename, block_samples=4096): + self.block_samples = block_samples self.fp = open(filename, 'rb') self.mf = mad.MadFile(self.fp) if not self.mf.total_time(): # Indicates a failed open. @@ -36,11 +37,12 @@ def close(self): if hasattr(self, 'mf'): del self.mf - def read_blocks(self, block_size=4096): + def read_blocks(self, block_size=None): """Generates buffers containing PCM data for the audio file. """ + block_samples = block_size or self.block_samples while True: - out = self.mf.read(block_size) + out = self.mf.read(block_samples) if not out: break yield out diff --git a/audioread/rawread.py b/audioread/rawread.py index 96fcd66..7126ef2 100644 --- a/audioread/rawread.py +++ b/audioread/rawread.py @@ -57,7 +57,6 @@ class RawAudioFile(object): """An AIFF, WAV, or Au file that can be read by the Python standard library modules ``wave``, ``aifc``, and ``sunau``. """ - block_samples = None def __init__(self, filename, block_samples=1024): self._fh = open(filename, 'rb') self.block_samples = block_samples @@ -110,7 +109,7 @@ def close(self): self._fh.close() def seek(self, pos): - """Seek to the position in the file""" + """Seek to a frame position in the file.""" # All three libraries have the same method for seeking self._file.setpos(pos) @@ -129,10 +128,14 @@ def duration(self): """Length of the audio in seconds (a float).""" return float(self._file.getnframes()) / self.samplerate + @property + def nframes(self): + """Gets the number of frames in the source file.""" + return self._file.getnframes() + def read_data(self, block_samples=None): - if block_samples is None: - block_samples = self.block_samples """Generates blocks of PCM data found in the file.""" + block_samples = block_samples or self.block_samples old_width = self._file.getsampwidth() while True: diff --git a/test/fixtures/make_test_wave.py b/test/fixtures/make_test_wave.py index 729dd20..37ea73e 100644 --- a/test/fixtures/make_test_wave.py +++ b/test/fixtures/make_test_wave.py @@ -13,7 +13,7 @@ def getData(): if __name__ == '__main__': - fout = wave.open('test/fixtures/wavetest.wave', 'w') + fout = wave.open('test/fixtures/wavetest.wav', 'w') data = getData() fout.setnchannels(1) fout.setframerate(44100) diff --git a/test/fixtures/mp3test.mp3 b/test/fixtures/mp3test.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..15f79d238c105f975b38db6e3a3441b0498bcb57 GIT binary patch literal 2551 zcmeHHX;f3!7QVR&Awa+|G=w}<0u%x=+>j_nQEwOpp{NW}B^Ct2q=;G+QD2iVPc;G} zp-=)uWHw9+v^*n09)vK8K(*}xR0v8D2UHZKNv&(WfBtyC-dgYbv8V6swfEX*pX2UK zMFC2f`1<&`DD*l2KzatBW^J~&p;2ro5cC)OQLMceiT}g>Xu8L+jw>uh9)JV@H7W4j z=Wy$DSo<85l@(2fD4X1>bUwlKlc6Skn4U5B$@{DJTA}t(9wyY?$9W=a(%WWxNqR8PZ+SB%0i!Crz>)p zjen;7_AN4Au4QRNS8+(wU|%#2iX7!MTcUqWGe|5k3%K}s2K!_z@cTdX07!iH$|-f_j6d8$TdO>VNQv0DD)ghn(g6Z9h@;|nE+1l z^rAy|I;l0UqlT}5Fo0tHj@iM&h>&KQJbg1zplt?XkSvglGDBf--H3QiXMs0CSFjNa zkktX6I2^!$HUNe-K+s|1%!20FmLL!|V0Q*2_pfjLDQ12*D9B}MJF9%D2bPr% zA)r_%%UBRLqUUTw856W0ou2*u%!?C`zMGvqv)ERny-%MWQa$pz{!Wzb$yqydK!{A_ zBL$4JAPTcfsB0Dt1n^vhiWz!7^^yn8B`wN-8uznDmj)q&EOY0maBZrH;- z*Jr&C4Rc*br%*MQP6+s%x-PF!jnxf&;)+{-P>2>6or|ShLzJtl7L*HaUqyO;Esp36 z?lzJ`U*qoT#1hHzm(sQ?FL<>)>*Q(smm`Bsw)d)7^L>lT;L^fH&;EojpE?B1o$sD7 zK3p~Obg!9RyPirm1wur2vH|$7|M~SlfVTyxreCa(R1nsXOpR(ep|Bb-1X@4m3Q?Ry zqM91#dld@X6uggc1JID0coni2ABXV30Z0d+N7h9wz+2S0!mQ=ldZq=9tNE_U@mm=W zr)r1n1!!Z2c{8DE^$uYf2p&ODX$(zq7-a*};@#go^a$*^sH#s*$_f%LS!JkSFMI5M zZqJ6t5G=8A=t{-nLz4+X>7&2y^W*;PQMkR>YOKyP1x1;Xk)cTznZyMSryf*eiue_A zCIhlDe8m}7L{}mL>DYwDG-4)$;rwH!3vG5XQsr6*#H#aLkSX#PdN8C&-Mv`D8*}w& zATZg=+93XU1v|21`s$tG%RXLFqXYB(VNv0ySuK$PeGzPzAnSI-SX(^qM3jE^7vt?( z#^oM)Bh3X-G-(;she#=TEPHpW$^K}6U<=h>cCXK8^HFKd!93;k-qv;1{X??7dzeeRrvkxk^!0X3{_||8}@V0^oJy0rSTF z`O^n>RCIRoE<5=YBEJWK1hfmjw078xZO+FUs)4jt!$HzrQ{~Fx+2+M>eA@Z}tTuxw zXl)d3{txDFW zs;~zq-=_o_{D2NdA#x31Y*j;je$L{llGQ~FbYe*R#Q>U!&|`k3+uapNKo)&?^Y+TL zc+Wp8FwV>rbXO7iSW!D9*(SL#xI8Ey;z4moH|VJY%{|=wY~IeH2lNXe*tyr)Ek#SR zU2SXhN8-$g-+I|stmQEO7aAw0Cny?Y|nko8RwI4o86x4y~i${+oJQzBk8o z?3(Z!0&k6*QY{)ZJ?bRXEu^ZNMOpu|k4OKO9|ErZ(f(Dy^#^hEBe#x?&aQpfpX*{l z+n?)CYJOSMrxIM zVE)K-Dc|FeyEM6SW?P<5gJE}0weJ&RUB>;CVynhYm!L_U?#)&xal z#GE%1-QizzL|V7EarmW9+v_i+GskWxEG-21)wU-sznrIR;@?zxI^GuS-}q#(WT!-@ z?T5IJbcjaY4N$-==iug-VZ^hzH!Ig-KCIW~FyYl&&sKQM|9!%IbPt_+YZ1C&SBy NYD1^nZ1(%_@F%+%x~TvF literal 0 HcmV?d00001 diff --git a/test/fixtures/wavetest.wave b/test/fixtures/wavetest.wav similarity index 100% rename from test/fixtures/wavetest.wave rename to test/fixtures/wavetest.wav diff --git a/test/test_audioread.py b/test/test_audioread.py index bef7665..7881942 100644 --- a/test/test_audioread.py +++ b/test/test_audioread.py @@ -1,23 +1,23 @@ import os import unittest import audioread -from audioread import rawread, macca -testMaccaFilename = os.path.abspath(os.path.join('test', 'fixtures', 'test.wav')) +numSamples = 512 +testFilename = os.path.abspath(os.path.join('test', 'fixtures', 'wavetest.wav')) rowLookup = [ b'\x00\x00', - b'\x9a\x19', - b'\x00@', - b'3s', + b'f2', + b'\x008', + b'3;', ] -numSamples = 512 -class TestAudioread(unittest.TestCase): +class TestAudioreadWav(unittest.TestCase): def test_audio_open_as_generator(self): result = [] - with audioread.audio_open(testMaccaFilename, block_samples=numSamples) as f: + with audioread.audio_open(testFilename, block_samples=numSamples) as f: + print('wav decode class', f.__class__) gen = f.read_data() try: while True: @@ -34,7 +34,7 @@ def test_audio_open_as_generator(self): def test_audio_open_as_forloop(self): result = [] - with audioread.audio_open(testMaccaFilename, block_samples=numSamples) as f: + with audioread.audio_open(testFilename, block_samples=numSamples) as f: self.assertEqual(f.nframes, 2048) for buf in f: result.append(buf) @@ -45,69 +45,24 @@ def test_audio_open_as_forloop(self): self.assertEqual(bytes(row[0:2]), rowLookup[i]) -class TestMacca(unittest.TestCase): - - def test_macca_as_generator(self): - result = [] - with macca.ExtAudioFile(testMaccaFilename, block_samples=numSamples) as f: - gen = f.read_data() - try: - while True: - data = next(gen) - result.append(data) - except StopIteration: - pass - - self.assertEqual(len(bytes(result[0])), numSamples*2) - self.assertEqual(len(rowLookup), len(result)) - for i, row in enumerate(result): - self.assertEqual(bytes(row[0:2]), rowLookup[i]) - - - def test_macca_as_forloop(self): - result = [] - with macca.ExtAudioFile(testMaccaFilename, block_samples=numSamples) as f: - self.assertEqual(f.nframes, 2048) - for buf in f: - result.append(buf) - - self.assertEqual(len(bytes(result[0])), numSamples*2) - self.assertEqual(len(rowLookup), len(result)) - for i, row in enumerate(result): - self.assertEqual(bytes(row[0:2]), rowLookup[i]) - - def test_seek(self): - result = [] - with macca.ExtAudioFile(testMaccaFilename, block_samples=numSamples) as input_file: - gen = input_file.read_data() - - # move forward - row = next(gen) - row = next(gen) - row = next(gen) - - # go back - input_file.seek(512) - row = next(gen) - self.assertEqual(bytes(row[0:2]), rowLookup[1]) - row = next(gen) - self.assertEqual(bytes(row[0:2]), rowLookup[2]) - - -testWaveFilename = os.path.abspath(os.path.join('test', 'fixtures', 'wavetest.wave')) -waveRowLookup = [ +mp3TestFilename = os.path.abspath(os.path.join('test', 'fixtures', 'sample.mp3')) +mp3RowLookup = [ + b'\x00\x00', + b'\x00\x00', + b'N\xff', + b'\xe8/', + b'.5', + b'\x089', b'\x00\x00', - b'f2', - b'\x008', - b'3;', ] -class TestRawRead(unittest.TestCase): +class TestAudioreadMp3(unittest.TestCase): - def test_open_as_generator(self): + def test_audio_open_as_generator(self): result = [] - with rawread.RawAudioFile(testWaveFilename, block_samples=numSamples) as input_file: - gen = input_file.read_data() + with audioread.audio_open(mp3TestFilename, block_samples=numSamples) as f: + print('Mp3 decode class', f.__class__) + gen = f.read_data() try: while True: data = next(gen) @@ -116,36 +71,22 @@ def test_open_as_generator(self): pass self.assertEqual(len(bytes(result[0])), numSamples*2) - self.assertEqual(len(rowLookup), len(result)) + self.assertEqual(len(mp3RowLookup), len(result)) for i, row in enumerate(result): - self.assertEqual(bytes(row[0:2]), waveRowLookup[i]) + self.assertEqual(bytes(row[0:2]), mp3RowLookup[i]) - def test_open_as_forloop(self): + def test_audio_open_as_forloop(self): result = [] - with audioread.rawread.RawAudioFile(testWaveFilename, block_samples=numSamples) as input_file: - for buf in input_file: + with audioread.audio_open(mp3TestFilename, block_samples=numSamples) as f: + # self.assertEqual(f.nframes, 4) + for buf in f: result.append(buf) + self.assertEqual(len(bytes(result[0])), numSamples*2) + self.assertEqual(len(mp3RowLookup), len(result)) for i, row in enumerate(result): - self.assertEqual(bytes(row[0:2]), waveRowLookup[i]) - - def test_seek(self): - result = [] - with rawread.RawAudioFile(testWaveFilename, block_samples=numSamples) as input_file: - gen = input_file.read_data() - - # move forward - row = next(gen) - row = next(gen) - row = next(gen) - - # go back - input_file.seek(512) - row = next(gen) - self.assertEqual(bytes(row[0:2]), waveRowLookup[1]) - row = next(gen) - self.assertEqual(bytes(row[0:2]), waveRowLookup[2]) + self.assertEqual(bytes(row[0:2]), mp3RowLookup[i]) if __name__ == '__main__': diff --git a/test/test_ffdec.py b/test/test_ffdec.py new file mode 100644 index 0000000..7a0c976 --- /dev/null +++ b/test/test_ffdec.py @@ -0,0 +1,72 @@ +import os +import unittest +import audioread +from audioread import ffdec + +testFilename = os.path.abspath(os.path.join('test', 'fixtures', 'sample.mp3')) +rowLookup = [ + b'\x01\x00', + b'w\x00', + b'\xf6&', + b'\xe8/', + b'v4', + b'f5', + b'~7', + b'\x9a7', + b'C\t', + b'\xfb\xff', +] +numSamples = 512 + +class TestFFDec(unittest.TestCase): + + def test_open_as_generator(self): + result = [] + with ffdec.FFmpegAudioFile(testFilename, block_samples=numSamples) as input_file: + print('input_file duration', input_file.duration) + gen = input_file.read_data() + try: + while True: + data = next(gen) + result.append(data) + except StopIteration: + pass + + self.assertEqual( + (len(rowLookup), len(bytes(result[0]))), + (len(result), numSamples) + ) + for i, row in enumerate(result): + self.assertEqual(bytes(row[0:2]), rowLookup[i]) + + + def test_open_as_forloop(self): + result = [] + with ffdec.FFmpegAudioFile(testFilename, block_samples=numSamples) as input_file: + for buf in input_file: + result.append(buf) + + self.assertEqual( + (len(rowLookup), len(bytes(result[0]))), + (len(result), numSamples) + ) + for i, row in enumerate(result): + self.assertEqual(bytes(row[0:2]), rowLookup[i]) + + @unittest.skip('wip') + def test_seek(self): + result = [] + with ffdec.FFmpegAudioFile(testFilename, block_samples=numSamples) as input_file: + gen = input_file.read_data() + + # move forward + row = next(gen) + row = next(gen) + row = next(gen) + + # go back + input_file.seek(512) + row = next(gen) + self.assertEqual(bytes(row[0:2]), rowLookup[1]) + row = next(gen) + self.assertEqual(bytes(row[0:2]), rowLookup[2]) diff --git a/test/test_gstdec.py b/test/test_gstdec.py new file mode 100644 index 0000000..d995b1e --- /dev/null +++ b/test/test_gstdec.py @@ -0,0 +1,70 @@ +import os +import unittest +import audioread + +gstAvailible = audioread._gst_available() +if gstAvailible: + from audioread import gstdec + + +testFilename = os.path.abspath(os.path.join('test', 'fixtures', 'sample.mp3')) +rowLookup = [ + b'\x01\x00', + b'w\x00', + b'\xf6&', + b'\xe8/', + b'v4', + b'f5', + b'~7', + b'\x9a7', + b'C\t', + b'\xfb\xff', +] +numSamples = 512 + +print('gstAvailible', gstAvailible) +@unittest.skipIf(not gstAvailible, 'Not supported') +class TestGstDec(unittest.TestCase): + + def test_open_as_generator(self): + result = [] + with gstdec.GstAudioFile(testFilename, block_samples=numSamples) as input_file: + gen = input_file.read_data() + try: + while True: + data = next(gen) + result.append(data) + except StopIteration: + pass + + self.assertEqual(len(bytes(result[0])), numSamples*2) + self.assertEqual(len(rowLookup), len(result)) + for i, row in enumerate(result): + self.assertEqual(bytes(row[0:2]), rowLookup[i]) + + + def test_open_as_forloop(self): + result = [] + with gstdec.GstAudioFile(testFilename, block_samples=numSamples) as input_file: + for buf in input_file: + result.append(buf) + + for i, row in enumerate(result): + self.assertEqual(bytes(row[0:2]), rowLookup[i]) + + def test_seek(self): + result = [] + with gstdec.GstAudioFile(testFilename, block_samples=numSamples) as input_file: + gen = input_file.read_data() + + # move forward + row = next(gen) + row = next(gen) + row = next(gen) + + # go back + input_file.seek(512) + row = next(gen) + self.assertEqual(bytes(row[0:2]), rowLookup[1]) + row = next(gen) + self.assertEqual(bytes(row[0:2]), rowLookup[2]) diff --git a/test/test_macca.py b/test/test_macca.py new file mode 100644 index 0000000..4353d54 --- /dev/null +++ b/test/test_macca.py @@ -0,0 +1,62 @@ +import os +import unittest +import audioread +from audioread import macca + + +testFilename = os.path.abspath(os.path.join('test', 'fixtures', 'wavetest.wav')) +rowLookup = [ + b'\x00\x00', + b'f2', + b'\x008', + b'3;', +] +numSamples = 512 + +class TestMacca(unittest.TestCase): + + def test_macca_as_generator(self): + result = [] + with macca.ExtAudioFile(testFilename, block_samples=numSamples) as f: + gen = f.read_data() + try: + while True: + data = next(gen) + result.append(data) + except StopIteration: + pass + + self.assertEqual(len(bytes(result[0])), numSamples*2) + self.assertEqual(len(rowLookup), len(result)) + for i, row in enumerate(result): + self.assertEqual(bytes(row[0:2]), rowLookup[i]) + + + def test_macca_as_forloop(self): + result = [] + with macca.ExtAudioFile(testFilename, block_samples=numSamples) as f: + self.assertEqual(f.nframes, 2048) + for buf in f: + result.append(buf) + + self.assertEqual(len(bytes(result[0])), numSamples*2) + self.assertEqual(len(rowLookup), len(result)) + for i, row in enumerate(result): + self.assertEqual(bytes(row[0:2]), rowLookup[i]) + + def test_seek(self): + result = [] + with macca.ExtAudioFile(testFilename, block_samples=numSamples) as input_file: + gen = input_file.read_data() + + # move forward + row = next(gen) + row = next(gen) + row = next(gen) + + # go back + input_file.seek(512) + row = next(gen) + self.assertEqual(bytes(row[0:2]), rowLookup[1]) + row = next(gen) + self.assertEqual(bytes(row[0:2]), rowLookup[2]) diff --git a/test/test_maddec.py b/test/test_maddec.py new file mode 100644 index 0000000..afd6763 --- /dev/null +++ b/test/test_maddec.py @@ -0,0 +1,69 @@ +import os +import unittest +import audioread +madAvailible = audioread._mad_available() +if madAvailible: + from audioread import maddec + +testFilename = os.path.abspath(os.path.join('test', 'fixtures', 'sample.mp3')) +rowLookup = [ + b'\x01\x00', + b'w\x00', + b'\xf6&', + b'\xe8/', + b'v4', + b'f5', + b'~7', + b'\x9a7', + b'C\t', + b'\xfb\xff', +] +numSamples = 512 +# print('madAvailible', madAvailible) +# @unittest.skipIf(not madAvailible, 'Not supported') + +@unittest.skip('WIP') +class TestMadDec(unittest.TestCase): + + def test_open_as_generator(self): + result = [] + with maddec.MadAudioFile(testFilename, block_samples=numSamples) as input_file: + gen = input_file.read_data() + try: + while True: + data = next(gen) + result.append(data) + except StopIteration: + pass + + self.assertEqual(len(bytes(result[0])), numSamples*2) + self.assertEqual(len(rowLookup), len(result)) + for i, row in enumerate(result): + self.assertEqual(bytes(row[0:2]), rowLookup[i]) + + + def test_open_as_forloop(self): + result = [] + with maddec.MadAudioFile(testFilename, block_samples=numSamples) as input_file: + for buf in input_file: + result.append(buf) + + for i, row in enumerate(result): + self.assertEqual(bytes(row[0:2]), rowLookup[i]) + + def test_seek(self): + result = [] + with maddec.MadAudioFile(testFilename, block_samples=numSamples) as input_file: + gen = input_file.read_data() + + # move forward + row = next(gen) + row = next(gen) + row = next(gen) + + # go back + input_file.seek(512) + row = next(gen) + self.assertEqual(bytes(row[0:2]), rowLookup[1]) + row = next(gen) + self.assertEqual(bytes(row[0:2]), rowLookup[2]) diff --git a/test/test_rawread.py b/test/test_rawread.py new file mode 100644 index 0000000..cb50ef4 --- /dev/null +++ b/test/test_rawread.py @@ -0,0 +1,60 @@ +import os +import unittest +import audioread +from audioread import rawread + + +testFilename = os.path.abspath(os.path.join('test', 'fixtures', 'wavetest.wav')) +rowLookup = [ + b'\x00\x00', + b'f2', + b'\x008', + b'3;', +] +numSamples = 512 + + +class TestRawRead(unittest.TestCase): + + def test_open_as_generator(self): + result = [] + with rawread.RawAudioFile(testFilename, block_samples=numSamples) as input_file: + gen = input_file.read_data() + try: + while True: + data = next(gen) + result.append(data) + except StopIteration: + pass + + self.assertEqual(len(bytes(result[0])), numSamples*2) + self.assertEqual(len(rowLookup), len(result)) + for i, row in enumerate(result): + self.assertEqual(bytes(row[0:2]), rowLookup[i]) + + + def test_open_as_forloop(self): + result = [] + with rawread.RawAudioFile(testFilename, block_samples=numSamples) as input_file: + for buf in input_file: + result.append(buf) + + for i, row in enumerate(result): + self.assertEqual(bytes(row[0:2]), rowLookup[i]) + + def test_seek(self): + result = [] + with rawread.RawAudioFile(testFilename, block_samples=numSamples) as input_file: + gen = input_file.read_data() + + # move forward + row = next(gen) + row = next(gen) + row = next(gen) + + # go back + input_file.seek(512) + row = next(gen) + self.assertEqual(bytes(row[0:2]), rowLookup[1]) + row = next(gen) + self.assertEqual(bytes(row[0:2]), rowLookup[2]) From 7ae1053f4db61898debb9b4e5d91fea36007913b Mon Sep 17 00:00:00 2001 From: Peter Conerly Date: Fri, 24 Aug 2018 13:30:35 -0700 Subject: [PATCH 4/5] investigation --- derp.py | 9 +++++++++ test/test_gstdec.py | 2 +- test/test_macca.py | 9 +++++++-- test/test_maddec.py | 7 +++---- 4 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 derp.py diff --git a/derp.py b/derp.py new file mode 100644 index 0000000..6832fab --- /dev/null +++ b/derp.py @@ -0,0 +1,9 @@ +import mad +import os +tf = os.path.abspath(os.path.join('test', 'fixtures', 'wavetest.wav')) + +fp = open(tf, 'rb') +mf = mad.MadFile(fp) + +print('mf.total_time', mf.total_time()) +print(mf.read()) diff --git a/test/test_gstdec.py b/test/test_gstdec.py index d995b1e..c6b0afb 100644 --- a/test/test_gstdec.py +++ b/test/test_gstdec.py @@ -7,7 +7,7 @@ from audioread import gstdec -testFilename = os.path.abspath(os.path.join('test', 'fixtures', 'sample.mp3')) +testFilename = os.path.abspath(os.path.join('test', 'fixtures', 'mp3test.mp3')) rowLookup = [ b'\x01\x00', b'w\x00', diff --git a/test/test_macca.py b/test/test_macca.py index 4353d54..8dbd8a9 100644 --- a/test/test_macca.py +++ b/test/test_macca.py @@ -1,10 +1,14 @@ import os import unittest import audioread -from audioread import macca +maccaAvailable = audioread._ca_available() +print('maccaAvailable', maccaAvailable) +if maccaAvailable: + from audioread import macca +PROJECT_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) +testFilename = os.path.abspath(os.path.join(PROJECT_DIR, 'test', 'fixtures', 'wavetest.wav')) -testFilename = os.path.abspath(os.path.join('test', 'fixtures', 'wavetest.wav')) rowLookup = [ b'\x00\x00', b'f2', @@ -13,6 +17,7 @@ ] numSamples = 512 +@unittest.skipIf(not maccaAvailable, 'Not supported') class TestMacca(unittest.TestCase): def test_macca_as_generator(self): diff --git a/test/test_maddec.py b/test/test_maddec.py index afd6763..5809247 100644 --- a/test/test_maddec.py +++ b/test/test_maddec.py @@ -5,7 +5,7 @@ if madAvailible: from audioread import maddec -testFilename = os.path.abspath(os.path.join('test', 'fixtures', 'sample.mp3')) +testFilename = os.path.abspath(os.path.join('test', 'fixtures', 'mp3test.mp3')) rowLookup = [ b'\x01\x00', b'w\x00', @@ -19,10 +19,8 @@ b'\xfb\xff', ] numSamples = 512 -# print('madAvailible', madAvailible) -# @unittest.skipIf(not madAvailible, 'Not supported') -@unittest.skip('WIP') +@unittest.skipIf(not madAvailible, 'Not supported') class TestMadDec(unittest.TestCase): def test_open_as_generator(self): @@ -51,6 +49,7 @@ def test_open_as_forloop(self): for i, row in enumerate(result): self.assertEqual(bytes(row[0:2]), rowLookup[i]) + @unittest.skip('WIP') def test_seek(self): result = [] with maddec.MadAudioFile(testFilename, block_samples=numSamples) as input_file: From 5cbfec6071ad70dd6a8e0c579cd4d42e5466a80c Mon Sep 17 00:00:00 2001 From: Peter Conerly Date: Wed, 29 Aug 2018 15:53:10 -0700 Subject: [PATCH 5/5] add sample.mp3 --- test/fixtures/sample.mp3 | Bin 0 -> 853 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/fixtures/sample.mp3 diff --git a/test/fixtures/sample.mp3 b/test/fixtures/sample.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..30edb48c2c3154dca532299d6cf61a992124eada GIT binary patch literal 853 zcmeZtF=k-^0p*b3U{@f`&%nU!lUSB!YOZHusAp(k0G5Ri|9?9iK;lA}o_T5cKo(FR z12Yh5FjNx)dkKO6gaF89pd*t(ji<7I6LfrGLH~coi5v}=ivR!MRcFYwUe{~dJ1j6v8} z(0}JK2F@RIwZ5BuV7j(t%NZcJ{cG>He_5|17d>0Ib+Y~cKY|7iTn-*~4CG~X)dxEC z#iYzmwHXsl9Jq70-Ojm|>AL73Ljpt4)2Di+oDWtm-OI;eutDgexlEn{Z}u{+qt_S; z#90EZ&V7nt=9#;C!RnN&OD&EwE@-iB`T6a2f2!0ztHw!OTc-)X|Nl3jbm5!lPLk64 zNe{pO|9_KjYqgccnw0zN_U;E-TldfU_>{Uo|NksVkY{3J{HlGvakq_4pjWJ4!i=14 zY#tHy?ya=leS44}JHt+Fz i>v&JKZ1ElM=R4zVPyM#K>f`9^YOH5zsb?BW2mk=2%6}pN literal 0 HcmV?d00001