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