-
Notifications
You must be signed in to change notification settings - Fork 11
/
files.py
102 lines (78 loc) · 3.33 KB
/
files.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
"""Module that handles file access and decoding to PCM.
It uses python-audiotools for the majority of the work done."""
import os.path
import audiotools
import audiotools.mp3
import garbage
class AudioError(Exception):
"""Exception raised when an error occurs in this module."""
pass
class GarbageAudioFile(garbage.Garbage):
"""Garbage class of the AudioFile class"""
def collect(self):
"""Tries to close the AudioFile resources when called."""
try:
self.item._reader.close()
except (audiotools.DecodingError):
pass
# Hack to kill zombies below
import gc, subprocess
try:
[item.poll() for item in gc.get_referrers(subprocess.Popen)
if isinstance(item, subprocess.Popen)]
except:
logger.warning("Exception occured in hack.")
# Hack to kill zombies above
return True
class AudioFile(object):
"""A Simple wrapper around the audiotools library.
This opens the filename given wraps the file in a PCMConverter that
turns it into PCM of format 44.1kHz, Stereo, 24-bit depth."""
def __init__(self, filename):
super(AudioFile, self).__init__()
self._reader = self._open_file(filename)
def read(self, size=4096, timeout=0.0):
"""Returns at most a string of size `size`.
The `timeout` argument is unused. But kept in for compatibility with
other read methods in the `audio` module."""
return self._reader.read(size).to_bytes(False, True)
def close(self):
"""Registers self for garbage collection. This method does not
close anything and only registers itself for colleciton."""
GarbageAudioFile(self)
def __getattr__(self, key):
try:
return getattr(self._reader, key)
except (AttributeError):
return getattr(self.file, key)
def progress(self, current, total):
"""Dummy progress function"""
pass
def _open_file(self, filename):
"""Open a file for reading and wrap it in several helpers."""
_, ext = os.path.splitext(filename)
if ext == '.mp3':
opener = audiotools.mp3.MP3Audio
else:
opener = audiotools.open
try:
reader = opener(filename)
except (audiotools.UnsupportedFile) as err:
raise AudioError("Unsupported file: " + filename.encode('utf8'))
except (ValueError) as err:
raise AudioError("Unsupported file: " + filename.encode('utf8'))
except:
raise AudioError("Unsupported file: " + filename.encode('utf8'))
self.file = reader
total_frames = reader.total_frames()
# Wrap in a PCMReader because we want PCM
reader = reader.to_pcm()
# Wrap in a converter
reader = audiotools.PCMConverter(reader, sample_rate=44100,
channels=2,
channel_mask=audiotools.ChannelMask(0x1 | 0x2),
bits_per_sample=24)
# And for file progress!
reader = audiotools.PCMReaderProgress(reader, total_frames,
self.progress)
return reader