Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWalter 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)
commitbade750a91fb15b316817d34ef405171d6e864c8 (patch)
tree01114881f5612fe410dd702fc0f71e9182737202
parent707adc01e62c17f4bf662ef896f7f12346fb05f3 (diff)
parent8944e441b24bf1e9a4877c11397b3f779165bb26 (diff)
Merge gitorious@git.sugarlabs.org:measure/mainline
-rw-r--r--config.py3
-rw-r--r--drawwaveform.py157
-rw-r--r--measure.py10
-rw-r--r--sensor_toolbar.py13
-rw-r--r--sound_toolbar.py63
-rw-r--r--textbox.py10
6 files changed, 174 insertions, 82 deletions
diff --git a/config.py b/config.py
index baedd62..e4f0a2e 100644
--- a/config.py
+++ b/config.py
@@ -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.
diff --git a/measure.py b/measure.py
index 45c8eff..e7d3a56 100644
--- a/measure.py
+++ b/measure.py
@@ -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:
diff --git a/textbox.py b/textbox.py
index 7ee9885..eb6406c 100644
--- a/textbox.py
+++ b/textbox.py
@@ -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"