diff options
author | Walter Bender <walter@walter-laptop.(none)> | 2009-11-20 18:07:57 (GMT) |
---|---|---|
committer | Walter Bender <walter@walter-laptop.(none)> | 2009-11-20 18:07:57 (GMT) |
commit | bade750a91fb15b316817d34ef405171d6e864c8 (patch) | |
tree | 01114881f5612fe410dd702fc0f71e9182737202 | |
parent | 707adc01e62c17f4bf662ef896f7f12346fb05f3 (diff) | |
parent | 8944e441b24bf1e9a4877c11397b3f779165bb26 (diff) |
Merge gitorious@git.sugarlabs.org:measure/mainline
-rw-r--r-- | config.py | 3 | ||||
-rw-r--r-- | drawwaveform.py | 157 | ||||
-rw-r--r-- | measure.py | 10 | ||||
-rw-r--r-- | sensor_toolbar.py | 13 | ||||
-rw-r--r-- | sound_toolbar.py | 63 | ||||
-rw-r--r-- | textbox.py | 10 |
6 files changed, 174 insertions, 82 deletions
@@ -25,9 +25,6 @@ from sugar.activity import activity MEASURE_ROOT = activity.get_bundle_path() ICONS_DIR = MEASURE_ROOT + '/icons' -#In milliseconds, the delay interval after which the waveform draw function will be queued" -REFRESH_TIME = 30 - #Multiplied with width and height to set placement of text TEXT_X_M = 0.65 TEXT_Y_M = 0.70 diff --git a/drawwaveform.py b/drawwaveform.py index bc0a788..3cf816f 100644 --- a/drawwaveform.py +++ b/drawwaveform.py @@ -45,13 +45,25 @@ class DrawWaveform(gtk.DrawingArea): __gtype_name__ = "MeasureDrawWaveform" + TRIGGER_NONE = 0 + TRIGGER_POS = 1 + TRIGGER_NEG = 2 + def __init__(self, input_frequency=48000): gtk.DrawingArea.__init__(self) + self.add_events(gtk.gdk.BUTTON_PRESS_MASK | \ + gtk.gdk.PROPERTY_CHANGE_MASK) + self._input_freq = input_frequency self.stroke_color = None - self.triggering = True + self.triggering = self.TRIGGER_NONE + self.trigger_xpos = 0.0 + self.trigger_ypos = 0.5 + + self.active = False + self._redraw_atom = gtk.gdk.atom_intern('MeasureRedraw') self.buffers = np.array([]) self.main_buffers = np.array([]) @@ -88,6 +100,7 @@ class DrawWaveform(gtk.DrawingArea): self.log_param5 = "" self._BACKGROUND_LINE_THICKNESS = 0.8 + self._TRIGGER_LINE_THICKNESS = 3 self._FOREGROUND_LINE_THICKNESS = 6 self.logging_status = False @@ -196,12 +209,16 @@ class DrawWaveform(gtk.DrawingArea): return True def set_context_on(self): - self.handler_unblock(self.expose_event_id) + if not self.context: + self.handler_unblock(self.expose_event_id) self.context = True + self._indirect_queue_draw() def set_context_off(self): + if self.context: + self.handler_block(self.expose_event_id) self.context = False - self.handler_block(self.expose_event_id) + self._indirect_queue_draw() def set_invert_state(self, invert_state): self.invert = invert_state @@ -217,9 +234,23 @@ class DrawWaveform(gtk.DrawingArea): def do_size_allocate(self, allocation): gtk.DrawingArea.do_size_allocate(self, allocation) self._update_mode() + if self.window is not None: + self._create_background_pixmap() + + def _indirect_queue_draw(self): + if self.window == None: + return + self.window.property_change(self._redraw_atom, self._redraw_atom, + 32, gtk.gdk.PROP_MODE_REPLACE, []); + + def do_property_notify_event(self, event): + if event.atom == self._redraw_atom: + self.queue_draw() def do_realize(self): gtk.DrawingArea.do_realize(self) + # force a native X window to exist + xid = self.window.xid colormap = self.get_colormap() @@ -235,9 +266,20 @@ class DrawWaveform(gtk.DrawingArea): self._line_gc[graph_id].set_foreground(clr) - # Background pixmap - clr = colormap.alloc_color(0, 65535, 0, False, False) + r, g, b = self.get_stroke_color_from_sugar() + clr = colormap.alloc_color(r, g, b, False, False) + self._trigger_line_gc = self.window.new_gc(foreground=clr) + self._trigger_line_gc.set_line_attributes( \ + self._TRIGGER_LINE_THICKNESS, gdk.LINE_SOLID, \ + gdk.CAP_ROUND, gdk.JOIN_BEVEL) + + self._trigger_line_gc.set_foreground(clr) + + self._create_background_pixmap() + + def _create_background_pixmap(self): + # Background pixmap back_surf = gdk.Pixmap(self.window, self._tick_size, self._tick_size) cr = back_surf.cairo_create() @@ -258,9 +300,9 @@ class DrawWaveform(gtk.DrawingArea): x = x + self._tick_size x = 0 - y = 0 + y = (self.allocation.height % self._tick_size) / 2 - self._tick_size - for j in range(0, 2): + for j in range(0, 3): cr.move_to(x, y) cr.rel_line_to(self._tick_size, 0) y = y + self._tick_size @@ -271,10 +313,16 @@ class DrawWaveform(gtk.DrawingArea): del cr self.window.set_back_pixmap(back_surf, False) + def do_button_press_event(self, event): + self.trigger_xpos = event.x / float(self.allocation.width) + self.trigger_ypos = event.y / float(self.allocation.height) + return True + def _expose(self, widget, event): """This function is the "expose" event handler and does all the drawing""" + #######################Real time drawing################################### - if self.context: + if self.context and self.active: #Iterate for each graph for graph_id in self.graph_id: @@ -283,23 +331,49 @@ class DrawWaveform(gtk.DrawingArea): samples = math.ceil(self.allocation.width/self.draw_interval) if len(buf) == 0: # We don't have enough data to plot. + self._indirect_queue_draw() return x_offset = 0 if (self.fft_show==False): - if self.triggering == True: - ints = buf[:-samples-3] <= 0 - ints &= buf[1:-samples-2] > 0 + if self.triggering != self.TRIGGER_NONE: + xpos = self.trigger_xpos + ypos = self.trigger_ypos + samples_to_end = int(samples*(1-xpos)) + + ypos -= 0.5 + ypos *= -32767.0 / self.y_mag + + x_offset = + self.allocation.width * xpos - (samples - samples_to_end) * self.draw_interval + + position = -1 + if self.triggering & self.TRIGGER_POS: + ints = buf[samples-samples_to_end:-samples_to_end-3] <= ypos + ints &= buf[samples-samples_to_end+1:-samples_to_end-2] > ypos + + ints = np.where(ints)[0] + if len(ints) > 0: + position = max(position, ints[-1]) + + if self.triggering & self.TRIGGER_NEG: + ints = buf[samples-samples_to_end:-samples_to_end-3] >= ypos + ints &= buf[samples-samples_to_end+1:-samples_to_end-2] < ypos + + ints = np.where(ints)[0] + if len(ints) > 0: + position = max(position, ints[-1]) - ints = np.where(ints)[0] - if len(ints) == 0: - ints = len(buf) - samples + if position == -1: + position = len(buf) - samples_to_end - 2 else: - ints = ints[-1] - x_offset = int((float(-buf[ints])/(buf[ints+1]-buf[ints]))*self.draw_interval+0.5) + position = position+samples-samples_to_end + try: + x_offset -= int((float(-buf[position]+ypos)/(buf[position+1]-buf[position]))*self.draw_interval+0.5) + except: + pass - data = buf[ints:ints+samples+2].astype(np.float64) + data = buf[position-samples+samples_to_end:position+samples_to_end+2].astype(np.float64) else: data = buf[-samples:].astype(np.float64) @@ -308,14 +382,20 @@ class DrawWaveform(gtk.DrawingArea): Fs = 48000 nfft = 65536 - # Multiply input with the window - np.multiply(buf, self.fft_window, buf) - - # Should be fast enough even without power of 2 stuff. - self.fftx = np.fft.rfft(buf) - self.fftx = abs(self.fftx) - data = np.multiply(self.fftx, 0.02, self.fftx) - ################################## + try: + # Multiply input with the window + np.multiply(buf, self.fft_window, buf) + + # Should be fast enough even without power of 2 stuff. + self.fftx = np.fft.rfft(buf) + self.fftx = abs(self.fftx) + data = np.multiply(self.fftx, 0.02, self.fftx) + ################################## + except ValueError: + # TODO: Figure out how this can happen. + # Shape mismatch between window and buf + self._indirect_queue_draw() + return True ################Scaling the values################### if config.CONTEXT == 2: @@ -331,17 +411,27 @@ class DrawWaveform(gtk.DrawingArea): ##########The actual drawing of the graph################## - lines = (np.arange(len(data), dtype='float32') * self.draw_interval) - x_offset + lines = (np.arange(len(data), dtype='float32') * self.draw_interval) + x_offset # We must make sure its int, or draw_lines will throw warnings # and these warnings are slow (even though they are filtered)! lines = zip(lines.astype('int'), data.astype('int')) - if self.type[graph_id] ==0: + if (self.fft_show==False): + if self.triggering != self.TRIGGER_NONE: + x = int(self.trigger_xpos * self.allocation.width) + y = int(self.trigger_ypos * self.allocation.height) + length = int(self._TRIGGER_LINE_THICKNESS * 3.5) + self.window.draw_line(self._trigger_line_gc, x - length, y, x + length, y) + self.window.draw_line(self._trigger_line_gc, x, y - length, x, y + length) + + if self.type[graph_id] == 0: self.window.draw_lines(self._line_gc[graph_id], lines) else: self.window.draw_points(self._line_gc[graph_id], lines) ############################################################ + + self._indirect_queue_draw() """ ## DISPLAYING FRAMERATE FOR DEBUGGGIN fr = 1.0/( time.time()-self.pr_time) @@ -373,6 +463,12 @@ class DrawWaveform(gtk.DrawingArea): self._update_mode() + def get_trigger(self): + return self.triggering + + def set_trigger(self, trigger): + self.triggering = trigger + def get_ticks(self): return self.allocation.width/float(self._tick_size) @@ -419,6 +515,13 @@ class DrawWaveform(gtk.DrawingArea): self.fft_window = None + def set_active(self, active): + self.active = active + self._indirect_queue_draw() + + def get_active(self): + return self.active + def get_stroke_color_from_sugar(self): """Returns in (r,g,b) format the stroke color from the Sugar profile""" # Hitting gconf is a large overhead. @@ -97,7 +97,7 @@ class MeasureActivity(activity.Activity): self.first = True - gobject.timeout_add(config.REFRESH_TIME, self.waveform_refresh) + self.wave.set_active(True) def set_show_hide_windows(self, window_id=1): """Shows the appropriate window identified by the window_id @@ -127,10 +127,6 @@ class MeasureActivity(activity.Activity): If 1 is returned means camera context""" return self.active_context_status - def waveform_refresh(self): - self.wave.queue_draw() - return self.active_status - def on_quit(self,data=None): self.audiograb.on_activity_quit() self.ji.on_quit() @@ -145,9 +141,9 @@ class MeasureActivity(activity.Activity): elif (self.props.active and not self.ACTIVE): self.audiograb.resume_grabbing() self.active_status = True - gobject.timeout_add(config.REFRESH_TIME, \ - self.waveform_refresh) + self.ACTIVE = self.props.active + self.wave.set_active(self.ACTIVE) """ Write the project to the Journal diff --git a/sensor_toolbar.py b/sensor_toolbar.py index 3e0beb5..224a780 100644 --- a/sensor_toolbar.py +++ b/sensor_toolbar.py @@ -72,7 +72,6 @@ class SensorToolbar(gtk.Toolbar): ####################### Voltage ###################### self._voltage = ToolButton('bias-off') self.insert(self._voltage, -1) - self._voltage.show() self._voltage.set_tooltip(_('Voltage Sensor')) self._voltage.connect('clicked', self.set_resistance_voltage_mode,\ 'voltage') @@ -81,7 +80,6 @@ class SensorToolbar(gtk.Toolbar): ####################### invert ####################### self._invert = ToolButton('invert') self.insert(self._invert, -1) - self._invert.show() self._invert.set_tooltip(_('Invert')) self._invert.connect('clicked', self._invert_control_cb) self.wave.set_invert_state(False) @@ -90,7 +88,6 @@ class SensorToolbar(gtk.Toolbar): separator = gtk.SeparatorToolItem() separator.props.draw = True self.insert(separator, -1) - separator.show() self.loginterval_img = gtk.Image() self.loginterval_img.set_from_file(config.ICONS_DIR + \ @@ -98,8 +95,6 @@ class SensorToolbar(gtk.Toolbar): self.loginterval_img_tool = gtk.ToolItem() self.loginterval_img_tool.add(self.loginterval_img) self.insert(self.loginterval_img_tool,-1) - self.loginterval_img.show() - self.loginterval_img_tool.show() ################### Logging Interval ################## self._loginterval_combo = ComboBox() @@ -116,14 +111,12 @@ class SensorToolbar(gtk.Toolbar): self._loginterval_tool = ToolComboBox(self._loginterval_combo) self.insert(self._loginterval_tool,-1) - self._loginterval_tool.show() self.logginginterval_status = '1second' ######################################################## ########### Start Logging/Stop Logging ################# self._record = ToolButton('media-record') self.insert(self._record, -1) - self._record.show() self._record.set_tooltip(_('Start Recording')) self._record.connect('clicked', self.record_control) ######################################################## @@ -133,16 +126,15 @@ class SensorToolbar(gtk.Toolbar): separator.props.draw = False separator.set_expand(True) self.insert(separator, -1) - separator.show() self.sample_value = gtk.Label("-") - self.sample_value.show() self.sample_value_toolitem = gtk.ToolItem() self.sample_value_toolitem.add(self.sample_value) self.insert(self.sample_value_toolitem, -1) - self.sample_value_toolitem.show() ######################################################## + self.show_all() + def set_sample_value(self, label="x"): self.sample_value.set_text(label) self.sample_value.show() @@ -269,6 +261,7 @@ class SensorToolbar(gtk.Toolbar): #self.boost_state = self.ag.get_mic_boost() self.ag.set_capture_gain(0) self.ag.set_mic_boost(False) + self.wave.set_trigger(self.wave.TRIGGER_NONE) def _update_string_for_textbox(self): self.string_for_textbox = "" diff --git a/sound_toolbar.py b/sound_toolbar.py index d20156b..ef679d5 100644 --- a/sound_toolbar.py +++ b/sound_toolbar.py @@ -71,7 +71,6 @@ class SoundToolbar(gtk.Toolbar): ###################### time ######################## self._time = ToolButton('domain-time2') self.insert(self._time, -1) - self._time.show() self._time.set_tooltip(_('Time base')) self._time.connect('clicked', self._timefreq_control_cb, True) #################################################### @@ -101,9 +100,10 @@ class SoundToolbar(gtk.Toolbar): self.freq_high_img_tool.add(self.freq_high_img) ################ frequency control ################# - self.adjustmentf = gtk.Adjustment(70, 10, 70 ,20, 20, 0.0) + self.adjustmentf = gtk.Adjustment(.5, 0, 1.0, 0.01, 0.1, 0) self.adjustmentf.connect("value_changed", self.cb_page_sizef) self._freq_range = gtk.HScale(self.adjustmentf) + self._freq_range.set_inverted(True) self._freq_range.set_draw_value(False) self._freq_range.set_update_policy(gtk.UPDATE_CONTINUOUS) self._freq_range.set_size_request(120,15) @@ -124,12 +124,10 @@ class SoundToolbar(gtk.Toolbar): separator = gtk.SeparatorToolItem() separator.props.draw = True self.insert(separator, -1) - separator.show() ################## pause button #################### self._pause = ToolButton('media-playback-pause') self.insert(self._pause, -1) - self._pause.show() self._pause.set_tooltip(_('Freeze the display')) self._pause.connect('clicked', self._pauseplay_control_cb) #################################################### @@ -145,8 +143,6 @@ class SoundToolbar(gtk.Toolbar): self.loginterval_img_tool = gtk.ToolItem() self.loginterval_img_tool.add(self.loginterval_img) self.insert(self.loginterval_img_tool,-1) - self.loginterval_img.show() - self.loginterval_img_tool.show() ################# Logging Interval ################# self._loginterval_combo = ComboBox() @@ -163,18 +159,37 @@ class SoundToolbar(gtk.Toolbar): self._loginterval_tool = ToolComboBox(self._loginterval_combo) self.insert(self._loginterval_tool,-1) - self._loginterval_tool.show() self.logginginterval_status = 'picture' #################################################### ############## Start Logging/Stop Logging ########## self._record = ToolButton('media-record') self.insert(self._record, -1) - self._record.show() self._record.set_tooltip(_('Start Recording')) self._record.connect('clicked', self.record_control) #################################################### + separator = gtk.SeparatorToolItem() + separator.props.draw = True + self.insert(separator, -1) + + ################# Trigger Setup ################# + self._trigger_combo = ComboBox() + self.trigger = [_('None'), _('Rising Edge') , _('Falling Edge') ] + self.trigger_conf = [wave.TRIGGER_NONE, wave.TRIGGER_POS, \ + wave.TRIGGER_NEG] + + self._trigger_changed_id = self._trigger_combo.connect("changed",\ + self.update_trigger_control) + + for i, s in enumerate(self.trigger): + self._trigger_combo.append_item(i, s, None) + self._trigger_combo.set_active(0) + + self._trigger_tool = ToolComboBox(self._trigger_combo) + self.insert(self._trigger_tool,-1) + self.show_all() + self._update_page_size() def record_control(self, data=None): @@ -242,6 +257,13 @@ class SoundToolbar(gtk.Toolbar): if (self._loginterval_combo.get_active() == 4): self.logginginterval_status = '30minute' + def update_trigger_control(self, *args): + active = self._trigger_combo.get_active() + if active == -1: + return + + self.wave.set_trigger(self.trigger_conf[active]) + def _pauseplay_control_cb(self, data=None): if self.ag.get_freeze_the_display()==True: self.ag.set_freeze_the_display(False) @@ -283,25 +305,13 @@ class SoundToolbar(gtk.Toolbar): def _update_page_size(self): self._update_page_size_id = None - if(self.adjustmentf.value>=10 and self.adjustmentf.value<20): - self._freq_range.set_value(10) - freq_div = 1000 - time_div = 0.001 - - if(self.adjustmentf.value>=20 and self.adjustmentf.value<46): - self._freq_range.set_value(30) - freq_div = 500 - time_div = 0.0005 - - if(self.adjustmentf.value>=46 and self.adjustmentf.value<62): - self._freq_range.set_value(50) - freq_div = 250 - time_div = 0.00025 + new_value = round(self.adjustmentf.value*100.0)/100.0 + if self.adjustmentf.value != new_value: + self.adjustmentf.value = new_value + return False - if(self.adjustmentf.value>=62 and self.adjustmentf.value<=70): - self._freq_range.set_value(70) - freq_div = 25 - time_div = 0.00005 + time_div = 0.001*max(self.adjustmentf.value, 0.05) + freq_div = 1000*max(self.adjustmentf.value, 0.01) self.wave.set_div(time_div, freq_div) @@ -328,6 +338,7 @@ class SoundToolbar(gtk.Toolbar): self.wave.set_fft_mode(False) self.wave.set_mag_params(self.g, self.y_mag) self._update_string_for_textbox() + self.update_trigger_control() def _update_string_for_textbox(self): if self.wave.get_fft_mode() == False: @@ -15,14 +15,10 @@ class TextBox: self.box_main = gtk.HBox() self.text_buffer = gtk.TextBuffer() self.text_box = gtk.TextView(self.text_buffer) - self.box_main.pack_start(self.text_box, False, True, 0) + self.box_main.pack_start(self.text_box, True, True, 0) self.box_main.show_all() #gobject.timeout_add(300, self.refresh_text_box) - - self._SIZE_X = 1200 - self._SIZE_Y = 50 - self._data_params = [] self._data_show_state = [] @@ -32,7 +28,6 @@ class TextBox: def _set_default_data_params(self): self._data_params.append('Time Scale') - def _set_default_data_show_state(self): @@ -41,9 +36,6 @@ class TextBox: def write_text(self, text_to_show=''): self.text_buffer.set_text(text_to_show) - self.text_box.set_size_request(self._SIZE_X, self._SIZE_Y) - self.text_box.realize() - def refresh_text_box(self): print "within textbox.py refresh_textbox called" |