##// END OF EJS Templates
implemented support for multiple channels in Audio
Erik Tollerud -
Show More
@@ -14,7 +14,7 b' class Audio(DisplayObject):'
14 14 When this object is returned by an input cell or passed to the
15 15 display function, it will result in Audio controls being displayed
16 16 in the frontend (only works in the notebook).
17
17
18 18 Parameters
19 19 ----------
20 20 data : numpy array, list, unicode, str or bytes
@@ -23,19 +23,19 b' class Audio(DisplayObject):'
23 23 * List of float or integer representing the waveform (mono)
24 24 * String containing the filename
25 25 * Bytestring containing raw PCM data or
26 * URL pointing to a file on the web.
27
26 * URL pointing to a file on the web.
27
28 28 If the array option is used the waveform will be normalized.
29
30 If a filename or url is used the format support will be browser
31 dependent.
29
30 If a filename or url is used the format support will be browser
31 dependent.
32 32 url : unicode
33 33 A URL to download the data from.
34 34 filename : unicode
35 35 Path to a local file to load the data from.
36 36 embed : boolean
37 37 Should the image data be embedded using a data URI (True) or should
38 the original source be referenced. Set this to True if you want the
38 the original source be referenced. Set this to True if you want the
39 39 audio to playable later with no internet connection in the notebook.
40 40
41 41 Default is `True`, unless the keyword argument `url` is set, then
@@ -75,17 +75,17 b' class Audio(DisplayObject):'
75 75 raise ValueError("No image data found. Expecting filename, url, or data.")
76 76 if embed is False and url is None:
77 77 raise ValueError("No url found. Expecting url when embed=False")
78
78
79 79 if url is not None and embed is not True:
80 80 self.embed = False
81 81 else:
82 82 self.embed = True
83 83 self.autoplay = autoplay
84 84 super(Audio, self).__init__(data=data, url=url, filename=filename)
85
85
86 86 if self.data is not None and not isinstance(self.data, bytes):
87 87 self.data = self._make_wav(data,rate)
88
88
89 89 def reload(self):
90 90 """Reload the raw data from file or URL."""
91 91 import mimetypes
@@ -98,32 +98,55 b' class Audio(DisplayObject):'
98 98 self.mimetype = mimetypes.guess_type(self.url)[0]
99 99 else:
100 100 self.mimetype = "audio/wav"
101
101
102 102 def _make_wav(self, data, rate):
103 103 """ Transform a numpy array to a PCM bytestring """
104 104 import struct
105 105 from io import BytesIO
106 106 import wave
107
107 108 try:
108 109 import numpy as np
109 data = np.array(data,dtype=float)
110 if len(data.shape) > 1:
111 raise ValueError("encoding of stereo PCM signals are unsupported")
110
111 data = np.array(data, dtype=float)
112 if len(data.shape) == 1:
113 nchan = 1
114 elif len(data.shape) == 2:
115 # In wave files,channels are interleaved. E.g.,
116 # "L1R1L2R2..." for stereo. See
117 # http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308(v=vs.85).aspx
118 # for channel ordering
119 nchan = data.shape[0]
120 data = data.T.ravel()
121 else:
122 raise ValueError('Array audio input must be a 1D or 2D array')
112 123 scaled = np.int16(data/np.max(np.abs(data))*32767).tolist()
113 124 except ImportError:
125 # check that it is a "1D" list
126 idata = iter(data) # fails if not an iterable
127 try:
128 iter(idata.next())
129 raise TypeError('Only lists of mono audio are '
130 'supported if numpy is not installed')
131 except TypeError:
132 # this means it's not a nested list, which is what we want
133 pass
114 134 maxabsvalue = float(max([abs(x) for x in data]))
115 scaled = [int(x/maxabsvalue*32767) for x in data]
135 scaled = [int(x/maxabsvalue*32767) for x in data]
136 nchan = 1
137
116 138 fp = BytesIO()
117 139 waveobj = wave.open(fp,mode='wb')
118 waveobj.setnchannels(1)
140 waveobj.setnchannels(nchan)
119 141 waveobj.setframerate(rate)
120 142 waveobj.setsampwidth(2)
121 143 waveobj.setcomptype('NONE','NONE')
122 144 waveobj.writeframes(b''.join([struct.pack('<h',x) for x in scaled]))
123 145 val = fp.getvalue()
124 146 waveobj.close()
125 return val
126
147
148 return val
149
127 150 def _data_and_metadata(self):
128 151 """shortcut for returning metadata with url information, if defined"""
129 152 md = {}
@@ -133,7 +156,7 b' class Audio(DisplayObject):'
133 156 return self.data, md
134 157 else:
135 158 return self.data
136
159
137 160 def _repr_html_(self):
138 161 src = """
139 162 <audio controls="controls" {autoplay}>
General Comments 0
You need to be logged in to leave comments. Login now