Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activity.py11
-rw-r--r--eye.py127
-rw-r--r--face.py119
-rw-r--r--fft_mouth.py60
-rw-r--r--mouth.py64
-rw-r--r--waveform_mouth.py52
6 files changed, 176 insertions, 257 deletions
diff --git a/activity.py b/activity.py
index e3cae54..b9d78b5 100644
--- a/activity.py
+++ b/activity.py
@@ -35,7 +35,8 @@ from sugar3.graphics.toolbarbox import ToolbarBox
from sugar3.activity.widgets import ActivityToolbarButton
from sugar3.activity.widgets import StopButton
-from shared_activity import SharedActivity
+#from shared_activity import SharedActivity
+from sugar3.activity import activity
from combobox import ComboBox
from toolitem import ToolWidget
from messenger import Messenger, SERVICE
@@ -79,12 +80,15 @@ class CursorFactory:
return self.cursors[cur_type]
-class SpeakActivity(SharedActivity):
+class SpeakActivity(activity.Activity):
+
def __init__(self, handle):
+ activity.Activity.__init__(self, handle)
+
self.notebook = Gtk.Notebook()
self.notebook.connect_after('map', self.__map_canvasactivity_cb)
- SharedActivity.__init__(self, self.notebook, SERVICE, handle)
+ #SharedActivity.__init__(self, self.notebook, SERVICE, handle)
self._cursor = None
self.set_cursor(Gdk.CursorType.LEFT_PTR)
@@ -208,6 +212,7 @@ class SpeakActivity(SharedActivity):
toolbox.toolbar.insert(StopButton(self), -1)
+ self.set_canvas(self.notebook)
toolbox.show_all()
self.toolbar_box = toolbox
diff --git a/eye.py b/eye.py
index fdb4a4f..2729388 100644
--- a/eye.py
+++ b/eye.py
@@ -27,55 +27,49 @@ from gi.repository import Gdk
from gi.repository import GObject
import math
-
class Eye(Gtk.DrawingArea):
+ """Eye."""
+
def __init__(self, fill_color):
Gtk.DrawingArea.__init__(self)
- self.frame = 0
- self.blink = False
+
self.x, self.y = 0, 0
self.fill_color = fill_color
-
- # listen for clicks
- self.add_events(Gdk.EventMask.BUTTON_PRESS_MASK)
- self.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK)
- self.connect("button_press_event", self._mouse_pressed_cb)
- self.connect("button_release_event", self._mouse_released_cb)
-
- def _mouse_pressed_cb(self, widget, event):
- self.blink = True
- self.queue_draw()
-
- def _mouse_released_cb(self, widget, event):
- self.blink = False
- self.queue_draw()
+
+ self.show_all()
def look_at(self, x, y):
+ """ Look. . ."""
+
self.x = x
self.y = y
self.queue_draw()
def look_ahead(self):
+ """ Look. . ."""
+
self.x = None
self.y = None
self.queue_draw()
# Thanks to xeyes :)
def computePupil(self):
- a = self.get_allocation()
+ """pupil."""
+
+ rect = self.get_allocation()
if self.x is None or self.y is None:
# look ahead, but not *directly* in the middle
- if a.x + a.width / 2 < self.get_allocation().width / 2:
- cx = a.width * 0.6
+ if rect.x + rect.width / 2 < rect.width / 2:
+ cx = rect.width * 0.6
else:
- cx = a.width * 0.4
- return cx, a.height * 0.6
+ cx = rect.width * 0.4
+ return cx, rect.height * 0.6
EYE_X, EYE_Y = self.translate_coordinates(
- self.get_toplevel(), a.width / 2, a.height / 2)
- EYE_HWIDTH = a.width
- EYE_HHEIGHT = a.height
+ self.get_toplevel(), rect.width / 2, rect.height / 2)
+ EYE_HWIDTH = rect.width
+ EYE_HHEIGHT = rect.height
BALL_DIST = EYE_HWIDTH / 4
dx = self.x - EYE_X
@@ -94,64 +88,49 @@ class Eye(Gtk.DrawingArea):
dx = dist * cosa
dy = dist * sina
- return a.width / 2 + dx, a.height / 2 + dy
+ return rect.width / 2 + dx, rect.height / 2 + dy
def do_draw(self, context):
- self.frame += 1
- bounds = self.get_allocation()
-
- eyeSize = min(bounds.width, bounds.height)
+ rect = self.get_allocation()
+
+ eyeSize = min(rect.width, rect.height)
+
outlineWidth = eyeSize / 20.0
pupilSize = eyeSize / 10.0
pupilX, pupilY = self.computePupil()
- dX = pupilX - bounds.width / 2.
- dY = pupilY - bounds.height / 2.
+ dX = pupilX - rect.width / 2.
+ dY = pupilY - rect.height / 2.
distance = math.sqrt(dX * dX + dY * dY)
limit = eyeSize / 2 - outlineWidth * 2 - pupilSize
if distance > limit:
- pupilX = bounds.width / 2 + dX * limit / distance
- pupilY = bounds.height / 2 + dY * limit / distance
-
- self.context = context
- #self.context.set_antialias(cairo.ANTIALIAS_NONE)
-
- #set a clip region for the expose event.
- #This reduces redrawing work (and time)
- self.context.rectangle(bounds.x,
- bounds.y,
- bounds.width,
- bounds.height)
- self.context.clip()
-
- # background
- self.context.set_source_rgba(*self.fill_color.get_rgba())
- self.context.rectangle(0, 0, bounds.width, bounds.height)
- self.context.fill()
-
+ pupilX = rect.width / 2 + dX * limit / distance
+ pupilY = rect.height / 2 + dY * limit / distance
+
+ context.set_source_rgba(*self.fill_color.get_rgba())
+ context.rectangle(0, 0, rect.width, rect.height)
+ context.fill()
+
# eye ball
- self.context.arc(bounds.width / 2,
- bounds.height / 2,
- eyeSize / 2 - outlineWidth / 2,
- 0,
- 360)
- self.context.set_source_rgb(1, 1, 1)
- self.context.fill()
-
+ context.set_source_rgb(1, 1, 1)
+ context.arc(rect.width / 2,
+ rect.height / 2,
+ eyeSize / 2 - outlineWidth / 2,
+ 0, 360)
+ context.fill()
+
# outline
- self.context.set_line_width(outlineWidth)
- self.context.arc(bounds.width / 2,
- bounds.height / 2,
- eyeSize / 2 - outlineWidth / 2,
- 0,
- 360)
- self.context.set_source_rgb(0, 0, 0)
- self.context.stroke()
-
+ context.set_source_rgb(0, 0, 0)
+ context.set_line_width(outlineWidth)
+ context.arc(rect.width / 2,
+ rect.height / 2,
+ eyeSize / 2 - outlineWidth / 2,
+ 0, 360)
+ context.stroke()
+
# pupil
- self.context.arc(pupilX, pupilY, pupilSize, 0, 360)
- self.context.set_source_rgb(0, 0, 0)
- self.context.fill()
-
- self.blink = False
-
+ context.set_source_rgb(0, 0, 0)
+ context.arc(pupilX, pupilY, pupilSize, 0, 360)
+ context.fill()
+
return True
+ \ No newline at end of file
diff --git a/face.py b/face.py
index dec365e..9768157 100644
--- a/face.py
+++ b/face.py
@@ -42,7 +42,7 @@ logger = logging.getLogger('speak')
FACE_PAD = 2
-class Status:
+class Status():
def __init__(self):
self.voice = voice.defaultVoice()
self.pitch = espeak.PITCH_MAX / 2
@@ -52,26 +52,26 @@ class Status:
self.mouth = mouth.Mouth
def serialize(self):
- eyes = {eye.Eye: 1,
- glasses.Glasses: 2}
+ eyes = {eye.Eye: 1, glasses.Glasses: 2}
+
mouths = {mouth.Mouth: 1,
- fft_mouth.FFTMouth: 2,
- waveform_mouth.WaveformMouth: 3}
+ fft_mouth.FFTMouth: 2,
+ waveform_mouth.WaveformMouth: 3}
return cjson.encode({
'voice': {'language': self.voice.language,
- 'name': self.voice.name},
+ 'name': self.voice.name},
'pitch': self.pitch,
'rate': self.rate,
'eyes': [eyes[i] for i in self.eyes],
'mouth': mouths[self.mouth]})
def deserialize(self, buf):
- eyes = {1: eye.Eye,
- 2: glasses.Glasses}
+ eyes = {1: eye.Eye, 2: glasses.Glasses}
+
mouths = {1: mouth.Mouth,
- 2: fft_mouth.FFTMouth,
- 3: waveform_mouth.WaveformMouth}
+ 2: fft_mouth.FFTMouth,
+ 3: waveform_mouth.WaveformMouth}
data = cjson.decode(buf)
self.voice = voice.Voice(data['voice']['language'],
@@ -94,49 +94,40 @@ class Status:
class View(Gtk.EventBox):
+ """Face."""
+
def __init__(self, fill_color=style.COLOR_BUTTON_GREY):
Gtk.EventBox.__init__(self)
+
self.status = Status()
self.fill_color = fill_color
-
- self.connect('size-allocate', self._size_allocate_cb)
-
+ self.modify_bg(0, self.fill_color.get_gdk_color())
+
self._audio = espeak.AudioGrab()
-
- # make an empty box for some eyes
- self._eyes = None
+
+ self._eyes = []
self._eyebox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
- self._eyebox.show()
-
- # make an empty box to put the mouth in
+
self._mouth = None
self._mouthbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
- self._mouthbox.show()
-
- # layout the screen
+
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
- box.set_homogeneous(False)
- box.pack_start(self._eyebox, expand=True, fill=True, padding=0)
- box.pack_start(self._mouthbox, expand=True, fill=True, padding=100)
- box.set_border_width(0)
- self.modify_bg(0, self.fill_color.get_gdk_color())
+
+ box.pack_start(self._eyebox, True, True, 0)
+ box.pack_start(self._mouthbox, True, True, 0)
+
self.add(box)
-
- self._peding = None
- self.connect('map', self.__map_cb)
-
- self.update()
-
- def __map_cb(self, widget):
- if self._peding:
- self.update(self._peding)
- self._peding = None
+ self.show_all()
def look_ahead(self):
+ """ Look. . ."""
+
if self._eyes:
map(lambda e: e.look_ahead(), self._eyes)
-
+
def look_at(self, pos=None):
+ """ Look. . ."""
+
if self._eyes:
if pos is None:
display = Gdk.Display.get_default()
@@ -144,54 +135,42 @@ class View(Gtk.EventBox):
else:
x, y = pos
map(lambda e, x=x, y=y: e.look_at(x, y), self._eyes)
-
+
def update(self, status=None):
- if not status:
- status = self.status
- else:
- # FIXME: view object has no attribute flags
- #if not self.flags() & Gtk.MAPPED:
- # self._peding = status
- # return
- self.status = status
-
- if self._eyes:
- for eye in self._eyes:
- self._eyebox.remove(eye)
- if self._mouth:
- self._mouthbox.remove(self._mouth)
-
+ """ Re packaged the mouth and eyes according to quantity."""
+
+ if status: self.status = status
+
+ for eye in self._eyes:
+ self._eyebox.remove(eye)
+
+ for child in self._mouthbox.get_children():
+ self._mouthbox.remove(child)
+
self._eyes = []
-
- for i in status.eyes:
+ for i in self.status.eyes:
eye = i(self.fill_color)
self._eyes.append(eye)
+
+ for eye in self._eyes:
self._eyebox.pack_start(eye, True, True, 0)
- eye.show()
- self._mouth = status.mouth(self._audio, self.fill_color)
- self._mouth.show()
- self._mouthbox.add(self._mouth)
-
- # enable mouse move events so we can track
- # the eyes while the mouse is over the mouth
- #self._mouth.add_events(gtk.gdk.POINTER_MOTION_MASK)
+ self._mouth = self.status.mouth(self._audio, self.fill_color)
+ self._mouthbox.pack_start(self._mouth, True, True, 0)
+
+ self.show_all()
def set_voice(self, voice):
self.status.voice = voice
self.say_notification(voice.friendlyname)
def say(self, something):
- self._audio.speak(self._peding or self.status, something)
+ self._audio.speak(self.status, something)
def say_notification(self, something):
- status = (self._peding or self.status).clone()
+ status = self.status.clone()
status.voice = voice.defaultVoice()
self._audio.speak(status, something)
def shut_up(self):
self._audio.stop_sound_device()
-
- def _size_allocate_cb(self, widget, allocation):
- self._mouthbox.set_size_request(-1,
- int(allocation.height / 2.5))
diff --git a/fft_mouth.py b/fft_mouth.py
index f91d900..1fae0cf 100644
--- a/fft_mouth.py
+++ b/fft_mouth.py
@@ -56,9 +56,9 @@ class FFTMouth(Mouth):
self.scaleX = "10"
self.scaleY = "10"
- def processBuffer(self, bounds):
- self.param1 = bounds.height / 65536.0
- self.param2 = bounds.height / 2.0
+ def processBuffer(self, rect):
+ self.param1 = rect.height / 65536.0
+ self.param2 = rect.height / 2.0
if(self.stop == False):
@@ -68,7 +68,7 @@ class FFTMouth(Mouth):
self.fftx = fft(self.newest_buffer, 256, -1)
self.fftx = self.fftx[0:self.freq_range * 2]
- self.draw_interval = bounds.width / (self.freq_range * 2.)
+ self.draw_interval = rect.width / (self.freq_range * 2.)
NumUniquePts = ceil((nfft + 1) / 2)
self.buffers = abs(self.fftx) * 0.02
@@ -85,8 +85,8 @@ class FFTMouth(Mouth):
temp_val_float = float(self.param1 * i * self.y_mag) +\
self.y_mag_bias_multiplier * self.param2
- if(temp_val_float >= bounds.height):
- temp_val_float = bounds.height - 25
+ if(temp_val_float >= rect.height):
+ temp_val_float = rect.height - 25
if(temp_val_float <= 0):
temp_val_float = 25
val.append(temp_val_float)
@@ -94,44 +94,28 @@ class FFTMouth(Mouth):
self.peaks = val
def do_draw(self, context):
- """This function is the "expose" event
- handler and does all the drawing."""
-
- bounds = self.get_allocation()
-
- self.processBuffer(bounds)
-
- #Create context, disable antialiasing
- self.context = context
- #self.context.set_antialias(cairo.ANTIALIAS_NONE)
-
- #set a clip region for the expose event.
- #This reduces redrawing work (and time)
- self.context.rectangle(bounds.x,
- bounds.y,
- bounds.width,
- bounds.height)
- self.context.clip()
-
+ rect = self.get_allocation()
+
+ self.processBuffer(rect)
+
# background
- self.context.set_source_rgba(*self.fill_color.get_rgba())
- self.context.rectangle(0, 0, bounds.width, bounds.height)
- self.context.fill()
-
+ context.set_source_rgba(*self.fill_color.get_rgba())
+ context.paint()
+
# Draw the waveform
- self.context.set_line_width(min(bounds.height / 10.0, 10))
- self.context.set_source_rgb(0, 0, 0)
+ context.set_line_width(min(rect.height / 10.0, 10))
+ context.set_source_rgb(0, 0, 0)
count = 0
for peak in self.peaks:
- self.context.line_to(bounds.width / 2 + count,
- bounds.height / 2 - peak)
+ context.line_to(rect.width / 2 + count,
+ rect.height / 2 - peak)
count += self.draw_interval
- self.context.stroke()
+ context.stroke()
count = 0
for peak in self.peaks:
- self.context.line_to(bounds.width / 2 - count,
- bounds.height / 2 - peak)
+ context.line_to(rect.width / 2 - count,
+ rect.height / 2 - peak)
count += self.draw_interval
- self.context.stroke()
-
+ context.stroke()
+
return True
diff --git a/mouth.py b/mouth.py
index 1155bb0..693d0ca 100644
--- a/mouth.py
+++ b/mouth.py
@@ -24,13 +24,14 @@
# This code is a super-stripped down version of the waveform view from Measure
from gi.repository import Gtk
+from gi.repository import Gdk
from struct import unpack
import numpy.core
class Mouth(Gtk.DrawingArea):
+
def __init__(self, audioSource, fill_color):
-
Gtk.DrawingArea.__init__(self)
self.buffers = []
@@ -38,7 +39,9 @@ class Mouth(Gtk.DrawingArea):
self.main_buffers = []
self.newest_buffer = []
self.fill_color = fill_color
-
+
+ self.show_all()
+
audioSource.connect("new-buffer", self._new_buffer)
def _new_buffer(self, obj, buf):
@@ -55,7 +58,7 @@ class Mouth(Gtk.DrawingArea):
self.queue_draw()
return True
- def processBuffer(self, bounds):
+ def processBuffer(self):
if len(self.main_buffers) == 0 or len(self.newest_buffer) == 0:
self.volume = 0
else:
@@ -63,46 +66,31 @@ class Mouth(Gtk.DrawingArea):
# numpy.core.min(self.main_buffers)
def do_draw(self, context):
- """This function is the "expose" event
- handler and does all the drawing."""
- bounds = self.get_allocation()
-
- self.processBuffer(bounds)
-
- #Create context, disable antialiasing
- self.context = context
- #self.context.set_antialias(cairo.ANTIALIAS_NONE)
-
- # set a clip region for the expose event.
- # This reduces redrawing work (and time)
- self.context.rectangle(bounds.x,
- bounds.y,
- bounds.width,
- bounds.height)
- self.context.clip()
-
+ rect = self.get_allocation()
+
+ self.processBuffer()
+
# background
- self.context.set_source_rgba(*self.fill_color.get_rgba())
- self.context.rectangle(0, 0, bounds.width, bounds.height)
- self.context.fill()
+ context.set_source_rgba(*self.fill_color.get_rgba())
+ context.paint()
# Draw the mouth
volume = self.volume / 30000.
- mouthH = volume * bounds.height
- mouthW = volume ** 2 * (bounds.width / 2.) + bounds.width / 2.
+ mouthH = volume * rect.height
+ mouthW = volume ** 2 * (rect.width / 2.) + rect.width / 2.
# T
# L R
# B
- Lx, Ly = bounds.width / 2 - mouthW / 2, bounds.height / 2
- Tx, Ty = bounds.width / 2, bounds.height / 2 - mouthH / 2
- Rx, Ry = bounds.width / 2 + mouthW / 2, bounds.height / 2
- Bx, By = bounds.width / 2, bounds.height / 2 + mouthH / 2
- self.context.set_line_width(min(bounds.height / 10.0, 10))
- self.context.move_to(Lx, Ly)
- self.context.curve_to(Tx, Ty, Tx, Ty, Rx, Ry)
- self.context.curve_to(Bx, By, Bx, By, Lx, Ly)
- self.context.set_source_rgb(0, 0, 0)
- self.context.close_path()
- self.context.stroke()
-
+ Lx, Ly = rect.width / 2 - mouthW / 2, rect.height / 2
+ Tx, Ty = rect.width / 2, rect.height / 2 - mouthH / 2
+ Rx, Ry = rect.width / 2 + mouthW / 2, rect.height / 2
+ Bx, By = rect.width / 2, rect.height / 2 + mouthH / 2
+ context.set_line_width(min(rect.height / 10.0, 10))
+ context.move_to(Lx, Ly)
+ context.curve_to(Tx, Ty, Tx, Ty, Rx, Ry)
+ context.curve_to(Bx, By, Bx, By, Lx, Ly)
+ context.set_source_rgb(0, 0, 0)
+ context.close_path()
+ context.stroke()
+
return True
diff --git a/waveform_mouth.py b/waveform_mouth.py
index 51c47f4..04d2c45 100644
--- a/waveform_mouth.py
+++ b/waveform_mouth.py
@@ -40,48 +40,32 @@ class WaveformMouth(Mouth):
self.y_mag = 0.7
def do_draw(self, context):
- """This function is the "expose"
- event handler and does all the drawing."""
-
- bounds = self.get_allocation()
- self.param1 = bounds.height / 65536.0
- self.param2 = bounds.height / 2.0
-
- #Create context, disable antialiasing
- self.context = context
- #self.context.set_antialias(cairo.ANTIALIAS_NONE)
-
- #set a clip region for the expose event.
- #This reduces redrawing work (and time)
- self.context.rectangle(bounds.x,
- bounds.y,
- bounds.width,
- bounds.height)
- self.context.clip()
-
+ rect = self.get_allocation()
+ self.param1 = rect.height / 65536.0
+ self.param2 = rect.height / 2.0
+
# background
- self.context.set_source_rgba(*self.fill_color.get_rgba())
- self.context.rectangle(0, 0, bounds.width, bounds.height)
- self.context.fill()
-
+ context.set_source_rgba(*self.fill_color.get_rgba())
+ context.paint()
+
# Draw the waveform
- self.context.set_line_width(min(bounds.height / 10.0, 10))
+ context.set_line_width(min(rect.height / 10.0, 10))
count = 0
buflen = float(len(self.main_buffers))
for value in self.main_buffers:
peak = float(self.param1 * value * self.y_mag) +\
self.y_mag_bias_multiplier * self.param2
-
- if peak >= bounds.height:
- peak = bounds.height
+
+ if peak >= rect.height:
+ peak = rect.height
if peak <= 0:
peak = 0
-
- x = count / buflen * bounds.width
- self.context.line_to(x, bounds.height - peak)
-
+
+ x = count / buflen * rect.width
+ context.line_to(x, rect.height - peak)
+
count += 1
- self.context.set_source_rgb(0, 0, 0)
- self.context.stroke()
-
+ context.set_source_rgb(0, 0, 0)
+ context.stroke()
+
return True