1
2 import re
3 import numpy
4 from gmisclib import die
5 from gmisclib import wavio
6 from gmisclib import Numeric_gpk as NG
7
11
12
13 NEARCLIP = 32500
14
15
16
17
18 -def wav_read(filename, channel=None, info={}):
19 """Quick and dirty way to read a single channel of audio from a
20 multichannel file. If the channel is not specified, either as an
21 argument or as info['Channel'], then it will pick whatever channel
22 has the largest amplitude. Needless to say, this is not entirely
23 reliable unless you know that the other channel is silent.
24 @param channel: which channel to use? It can be a string name, an integer column number
25 or None.
26 @param info: a dictionary with miscellaneous metadata. C{info['Channel']} is inspected.
27 @type info: C{dict}.
28 @type channel: C{string}, C{int}, or C{None}.
29 @return: audio data with header information
30 A gpk_img data structure holding the audio and header information.
31 C{hdr['AudioChannel']}, C{hdr['Trouble']} and C{hdr['WhyAudioChannel']} are set.
32 @rtype: gpkimgclass.gpk_img
33 @except BadChannel: when you ask for a channel that isn't there.
34 @note: Channel numbers start with zero!
35 """
36 if channel is None:
37 channel = info.get('Channel', None)
38
39 x = wavio.read(filename)
40 nch0 = x.d.shape[1]
41 trouble = []
42 if channel is None and x.d.shape[1] > 1:
43 assert x.d.shape[1] < 1000
44 rms = NG.block_stdev(x.d)
45 channel = numpy.argmax(rms)
46 x.d = x.d.take([channel], axis=1)
47 assert len(x.d.shape) == 2
48 die.info('Taking data from channel %d' % channel)
49 if rms[1-channel] > 0.1*rms[channel]:
50 die.warn('Warning: channel %d is comparable: MAD=%.2g/%.2g'
51 % (1-channel, rms[1-channel], rms[channel])
52 )
53 x.hdr['WhyAudioChannel'] = 'It was slightly louder'
54 trouble.append('Ambiguous channel')
55 else:
56 x.hdr['WhyAudioChannel'] = 'It was much louder'
57 elif channel is None and x.d.shape[1]==1:
58 x.hdr['WhyAudioChannel'] = 'There was only one'
59 channel = 0
60 elif channel=='mono':
61 assert x.d.shape[1]==1
62 x.hdr['WhyAudioChannel'] = 'There was only one'
63 channel = 0
64 elif 0 <= channel < x.d.shape[1]:
65 x.d = x.d.take([channel], axis=1)
66 x.hdr['WhyAudioChannel'] = 'Specified in g_audioprep.py'
67 else:
68 raise BadChannel, "Channel=%s but available channels are %s" % (channel, range(x.d.shape[1]))
69
70
71
72 if NG.N_maximum(x.column(0)) > NEARCLIP or NG.N_minimum(x.column(0))< -NEARCLIP:
73 da = numpy.absolute(x.column(0))
74 die.warn("Data is near clipping: maximum abs(value)=%d, %.1f%% near clipping"
75 % (NG.N_maximum(da), numpy.sum(numpy.greater(da, NEARCLIP))/float(da.shape[0])))
76 trouble.append('Near clipping')
77
78 x.hdr['Trouble'] = ','.join(trouble)
79 assert 0 <= channel < nch0
80 x.hdr['AudioChannel'] = channel
81 assert x.d.shape[1] == 1
82 return x
83
84
85 _nmparse = re.compile(r'(.*)\[([0-9_a-zA-Z]+)\]$')
87 """Splits filenames in the form pathname[channel] into a pathname
88 and a channel.
89 """
90 m = _nmparse.match(filename)
91 if m:
92 name = m.group(1)
93 try:
94 channel = int(m.group(2))
95 except ValueError:
96 channel = m.group(2)
97 else:
98 name = filename
99 channel = None
100 return (name, channel)
101
102
104 """Deal with filenames in the form path/name[channel].
105 """
106 name, channel = splitname(filename)
107 try:
108 rv = wav_read(name, channel=channel, info={})
109 except IOError, x:
110 raise IOError(*(x.args + ('From dirty_io.wav_read2', 'Filename=%s' % filename)))
111 return rv
112