~ubuntu-branches/ubuntu/utopic/python-chaco/utopic

« back to all changes in this revision

Viewing changes to examples/demo/advanced/spec_waterfall.py

  • Committer: Package Import Robot
  • Author(s): Andrew Starr-Bochicchio
  • Date: 2014-06-01 17:04:08 UTC
  • mfrom: (7.2.5 sid)
  • Revision ID: package-import@ubuntu.com-20140601170408-m86xvdjd83a4qon0
Tags: 4.4.1-1ubuntu1
* Merge from Debian unstable. Remaining Ubuntu changes:
 - Let the binary-predeb target work on the usr/lib/python* directory
   as we don't have usr/share/pyshared anymore.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""
2
 
This plot displays the audio spectrum from the microphone.
3
 
 
4
 
Based on updating_plot.py
5
 
"""
6
 
# Major library imports
7
 
import pyaudio
8
 
from numpy import zeros, linspace, short, fromstring, transpose, array
9
 
from scipy import fft
10
 
 
11
 
# Enthought library imports
12
 
from enable.api import Window, Component, ComponentEditor
13
 
from traits.api import HasTraits, Instance, List
14
 
from traitsui.api import Item, Group, View, Handler
15
 
from pyface.timer.api import Timer
16
 
 
17
 
# Chaco imports
18
 
from chaco.api import (Plot, ArrayPlotData, HPlotContainer, VPlotContainer,
19
 
    AbstractMapper, LinePlot, LinearMapper, DataRange1D)
20
 
 
21
 
NUM_SAMPLES = 1024
22
 
SAMPLING_RATE = 11025
23
 
SPECTROGRAM_LENGTH = 50
24
 
 
25
 
class WaterfallRenderer(LinePlot):
26
 
 
27
 
    # numpy arrays of the same length
28
 
    values = List(args=[])
29
 
 
30
 
    # Maps each array in values into a contrained, short screen space
31
 
    y2_mapper = Instance(AbstractMapper)
32
 
 
33
 
    _cached_data_pts = List()
34
 
    _cached_screen_pts = List()
35
 
 
36
 
    def _gather_points(self):
37
 
        if not self._cache_valid:
38
 
            if not self.index or len(self.values) == 0:
39
 
                return
40
 
 
41
 
            index = self.index.get_data()
42
 
            values = self.values
43
 
 
44
 
            numindex = len(index)
45
 
            if numindex == 0 or all(len(v)==0 for v in values) or all(numindex != len(v) for v in values):
46
 
                self._cached_data_pts = []
47
 
                self._cache_valid = True
48
 
 
49
 
            self._cached_data_pts = [transpose(array((index, v))) for v in values]
50
 
            self._cache_value = True
51
 
        return
52
 
 
53
 
    def get_screen_points(self):
54
 
        self._gather_points()
55
 
        return [self.map_screen(pts, i) for i, pts in enumerate(self._cached_data_pts)]
56
 
 
57
 
    def map_screen(self, data_array, data_offset=None):
58
 
        """ data_offset, if provided, is a float that will be mapped
59
 
        into screen space using self.value_mapper and then added to
60
 
        mapping data_array with y2_mapper.  If data_offset is not
61
 
        provided, then y2_mapper is used.
62
 
        """
63
 
        if len(data_array) == 0:
64
 
            return []
65
 
        x_ary, y_ary = transpose(data_array)
66
 
        sx = self.index_mapper.map_screen(x_ary)
67
 
        if data_offset is not None:
68
 
            dy = self.value_mapper.map_screen(data_offset)
69
 
            sy = self.y2_mapper.map_screen(y_ary) + dy
70
 
        else:
71
 
            sy = self.value_mapper.map_screen(y_ary)
72
 
 
73
 
        if self.orientation == "h":
74
 
            return transpose(array((sx, sy)))
75
 
        else:
76
 
            return transpose(array((sy, sx)))
77
 
 
78
 
#============================================================================
79
 
# Create the Chaco plot.
80
 
#============================================================================
81
 
 
82
 
def _create_plot_component(obj):
83
 
    # Setup the spectrum plot
84
 
    frequencies = linspace(0.0, float(SAMPLING_RATE)/2, num=NUM_SAMPLES/2)
85
 
    obj.spectrum_data = ArrayPlotData(frequency=frequencies)
86
 
    empty_amplitude = zeros(NUM_SAMPLES/2)
87
 
    obj.spectrum_data.set_data('amplitude', empty_amplitude)
88
 
 
89
 
    obj.spectrum_plot = Plot(obj.spectrum_data)
90
 
    spec_renderer = obj.spectrum_plot.plot(("frequency", "amplitude"), name="Spectrum",
91
 
                           color="red")[0]
92
 
    obj.spectrum_plot.padding = 50
93
 
    obj.spectrum_plot.title = "Spectrum"
94
 
    spec_range = obj.spectrum_plot.plots.values()[0][0].value_mapper.range
95
 
    spec_range.low = 0.0
96
 
    spec_range.high = 5.0
97
 
    obj.spectrum_plot.index_axis.title = 'Frequency (hz)'
98
 
    obj.spectrum_plot.value_axis.title = 'Amplitude'
99
 
 
100
 
    # Time Series plot
101
 
    times = linspace(0.0, float(NUM_SAMPLES)/SAMPLING_RATE, num=NUM_SAMPLES)
102
 
    obj.time_data = ArrayPlotData(time=times)
103
 
    empty_amplitude = zeros(NUM_SAMPLES)
104
 
    obj.time_data.set_data('amplitude', empty_amplitude)
105
 
 
106
 
    obj.time_plot = Plot(obj.time_data)
107
 
    obj.time_plot.plot(("time", "amplitude"), name="Time", color="blue")
108
 
    obj.time_plot.padding = 50
109
 
    obj.time_plot.title = "Time"
110
 
    obj.time_plot.index_axis.title = 'Time (seconds)'
111
 
    obj.time_plot.value_axis.title = 'Amplitude'
112
 
    time_range = obj.time_plot.plots.values()[0][0].value_mapper.range
113
 
    time_range.low = -0.2
114
 
    time_range.high = 0.2
115
 
 
116
 
    # Spectrogram plot
117
 
    values = [zeros(NUM_SAMPLES/2) for i in xrange(SPECTROGRAM_LENGTH)]
118
 
    p = WaterfallRenderer(index = spec_renderer.index, values = values,
119
 
            index_mapper = LinearMapper(range = obj.spectrum_plot.index_mapper.range),
120
 
            value_mapper = LinearMapper(range = DataRange1D(low=0, high=SPECTROGRAM_LENGTH)),
121
 
            y2_mapper = LinearMapper(low_pos=0, high_pos=8,
122
 
                            range=DataRange1D(low=0, high=15)),
123
 
            )
124
 
    spectrogram_plot = p
125
 
    obj.spectrogram_plot = p
126
 
    dummy = Plot()
127
 
    dummy.padding = 50
128
 
    dummy.index_axis.mapper.range = p.index_mapper.range
129
 
    dummy.index_axis.title = "Frequency (hz)"
130
 
    dummy.add(p)
131
 
 
132
 
    container = HPlotContainer()
133
 
    container.add(obj.spectrum_plot)
134
 
    container.add(obj.time_plot)
135
 
 
136
 
    c2 = VPlotContainer()
137
 
    c2.add(dummy)
138
 
    c2.add(container)
139
 
 
140
 
    return c2
141
 
 
142
 
 
143
 
def get_audio_data():
144
 
    pa = pyaudio.PyAudio()
145
 
    stream = pa.open(format=pyaudio.paInt16, channels=1, rate=SAMPLING_RATE,
146
 
                     input=True, frames_per_buffer=NUM_SAMPLES)
147
 
    audio_data  = fromstring(stream.read(NUM_SAMPLES), dtype=short)
148
 
    stream.close()
149
 
    normalized_data = audio_data / 32768.0
150
 
    return (abs(fft(normalized_data))[:NUM_SAMPLES/2], normalized_data)
151
 
 
152
 
 
153
 
# HasTraits class that supplies the callable for the timer event.
154
 
class TimerController(HasTraits):
155
 
 
156
 
    def onTimer(self, *args):
157
 
        spectrum, time = get_audio_data()
158
 
        self.spectrum_data.set_data('amplitude', spectrum)
159
 
        self.time_data.set_data('amplitude', time)
160
 
        spec_data = self.spectrogram_plot.values[1:] + [spectrum]
161
 
        self.spectrogram_plot.values = spec_data
162
 
        self.spectrum_plot.request_redraw()
163
 
        return
164
 
 
165
 
#============================================================================
166
 
# Attributes to use for the plot view.
167
 
size = (900,850)
168
 
title = "Audio Spectrum Waterfall"
169
 
 
170
 
#============================================================================
171
 
# Demo class that is used by the demo.py application.
172
 
#============================================================================
173
 
 
174
 
class DemoHandler(Handler):
175
 
 
176
 
    def closed(self, info, is_ok):
177
 
        """ Handles a dialog-based user interface being closed by the user.
178
 
        Overridden here to stop the timer once the window is destroyed.
179
 
        """
180
 
 
181
 
        info.object.timer.Stop()
182
 
        return
183
 
 
184
 
class Demo(HasTraits):
185
 
 
186
 
    plot = Instance(Component)
187
 
 
188
 
    controller = Instance(TimerController, ())
189
 
 
190
 
    timer = Instance(Timer)
191
 
 
192
 
    traits_view = View(
193
 
                    Group(
194
 
                        Item('plot', editor=ComponentEditor(size=size),
195
 
                             show_label=False),
196
 
                        orientation = "vertical"),
197
 
                    resizable=True, title=title,
198
 
                    width=size[0], height=size[1]+25,
199
 
                    handler=DemoHandler
200
 
                    )
201
 
 
202
 
    def __init__(self, **traits):
203
 
        super(Demo, self).__init__(**traits)
204
 
        self.plot = _create_plot_component(self.controller)
205
 
 
206
 
    def edit_traits(self, *args, **kws):
207
 
        # Start up the timer! We should do this only when the demo actually
208
 
        # starts and not when the demo object is created.
209
 
        self.timer = Timer(20, self.controller.onTimer)
210
 
        return super(Demo, self).edit_traits(*args, **kws)
211
 
 
212
 
    def configure_traits(self, *args, **kws):
213
 
        # Start up the timer! We should do this only when the demo actually
214
 
        # starts and not when the demo object is created.
215
 
        self.timer = Timer(20, self.controller.onTimer)
216
 
        return super(Demo, self).configure_traits(*args, **kws)
217
 
 
218
 
 
219
 
popup = Demo()
220
 
 
221
 
if __name__ == "__main__":
222
 
    popup.configure_traits()