Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Speak.activity/activity.py
diff options
context:
space:
mode:
Diffstat (limited to 'Speak.activity/activity.py')
-rw-r--r--Speak.activity/activity.py478
1 files changed, 0 insertions, 478 deletions
diff --git a/Speak.activity/activity.py b/Speak.activity/activity.py
deleted file mode 100644
index 18a2e24..0000000
--- a/Speak.activity/activity.py
+++ /dev/null
@@ -1,478 +0,0 @@
-# Speak.activity
-# A simple front end to the espeak text-to-speech engine on the XO laptop
-# http://wiki.laptop.org/go/Speak
-#
-# Copyright (C) 2008 Joshua Minor
-# This file is part of Speak.activity
-#
-# Parts of Speak.activity are based on code from Measure.activity
-# Copyright (C) 2007 Arjun Sarwal - arjun@laptop.org
-#
-# Speak.activity is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Speak.activity is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with Speak.activity. If not, see <http://www.gnu.org/licenses/>.
-
-
-from sugar.activity import activity
-from sugar.presence import presenceservice
-import logging
-import gtk
-import gobject
-import pango
-import cjson
-from gettext import gettext as _
-
-from sugar.graphics.toolbutton import ToolButton
-from sugar.graphics.toggletoolbutton import ToggleToolButton
-from sugar.graphics.radiotoolbutton import RadioToolButton
-
-from toolkit.toolitem import ToolWidget
-from toolkit.combobox import ComboBox
-from toolkit.toolbarbox import ToolbarBox
-from toolkit.activity import SharedActivity
-from toolkit.activity_widgets import *
-
-import eye
-import glasses
-import mouth
-import fft_mouth
-import waveform_mouth
-import voice
-import face
-import brain
-import chat
-import espeak
-from messenger import Messenger, SERVICE
-
-logger = logging.getLogger('speak')
-
-MODE_TYPE = 1
-MODE_BOT = 2
-MODE_CHAT = 3
-
-
-class SpeakActivity(SharedActivity):
- def __init__(self, handle):
- self.notebook = gtk.Notebook()
-
- SharedActivity.__init__(self, self.notebook, SERVICE, handle)
-
- self._mode = MODE_TYPE
- self.numeyesadj = None
-
- # make an audio device for playing back and rendering audio
- self.connect( "notify::active", self._activeCb )
-
- # make a box to type into
- self.entrycombo = gtk.combo_box_entry_new_text()
- self.entrycombo.connect("changed", self._combo_changed_cb)
- self.entry = self.entrycombo.child
- self.entry.set_editable(True)
- self.entry.connect('activate', self._entry_activate_cb)
- self.entry.connect("key-press-event", self._entry_key_press_cb)
- self.input_font = pango.FontDescription(str='sans bold 24')
- self.entry.modify_font(self.input_font)
-
- self.face = face.View()
- self.face.show()
-
- # layout the screen
- box = gtk.VBox(homogeneous=False)
- box.pack_start(self.face)
- box.pack_start(self.entrycombo, expand=False)
-
- self.add_events(gtk.gdk.POINTER_MOTION_HINT_MASK
- | gtk.gdk.POINTER_MOTION_MASK)
- self.connect("motion_notify_event", self._mouse_moved_cb)
-
- box.add_events(gtk.gdk.BUTTON_PRESS_MASK)
- box.connect("button_press_event", self._mouse_clicked_cb)
-
- # desktop
- self.notebook.show()
- self.notebook.props.show_border = False
- self.notebook.props.show_tabs = False
-
- box.show_all()
- self.notebook.append_page(box)
-
- self.chat = chat.View()
- self.chat.show_all()
- self.notebook.append_page(self.chat)
-
- # make the text box active right away
- self.entry.grab_focus()
-
- self.entry.connect("move-cursor", self._cursor_moved_cb)
- self.entry.connect("changed", self._cursor_moved_cb)
-
- # toolbar
-
- toolbox = ToolbarBox()
-
- toolbox.toolbar.insert(ActivityToolbarButton(self), -1)
-
- separator = gtk.SeparatorToolItem()
- separator.set_draw(False)
- toolbox.toolbar.insert(separator, -1)
-
- self.voices = ComboBox()
- for name in sorted(voice.allVoices().keys()):
- self.voices.append_item(voice.allVoices()[name], name)
- self.voices.select(voice.defaultVoice())
- all_voices = self.voices.get_model()
- brain_voices = brain.get_voices()
-
- mode_type = RadioToolButton(
- named_icon='mode-type',
- tooltip=_('Lessons'))
- mode_type.connect('toggled', self.__toggled_mode_type_cb, all_voices)
- toolbox.toolbar.insert(mode_type, -1)
-
- mode_robot = RadioToolButton(
- named_icon='mode-robot',
- group=mode_type,
- tooltip=_('Robot'))
- mode_robot.connect('toggled', self.__toggled_mode_robot_cb,
- brain_voices)
- toolbox.toolbar.insert(mode_robot, -1)
-
- mode_chat = RadioToolButton(
- named_icon='mode-chat',
- group=mode_type,
- tooltip=_('Chat'))
- mode_chat.connect('toggled', self.__toggled_mode_chat_cb, all_voices)
- toolbox.toolbar.insert(mode_chat, -1)
-
- separator = gtk.SeparatorToolItem()
- toolbox.toolbar.insert(separator, -1)
-
- voices_toolitem = ToolWidget(widget=self.voices)
- toolbox.toolbar.insert(voices_toolitem, -1)
-
- voice_button = ToolbarButton(
- page=self.make_voice_bar(),
- label=_('Voice'),
- icon_name='voice')
- toolbox.toolbar.insert(voice_button, -1)
-
- face_button = ToolbarButton(
- page=self.make_face_bar(),
- label=_('Face'),
- icon_name='face')
- toolbox.toolbar.insert(face_button, -1)
-
- separator = gtk.SeparatorToolItem()
- separator.set_draw(False)
- separator.set_expand(True)
- toolbox.toolbar.insert(separator, -1)
-
- toolbox.toolbar.insert(StopButton(self), -1)
-
- toolbox.show_all()
- self.toolbar_box = toolbox
-
- def new_instance(self):
- self.voices.connect('changed', self.__changed_voices_cb)
- self.pitchadj.connect("value_changed", self.pitch_adjusted_cb, self.pitchadj)
- self.rateadj.connect("value_changed", self.rate_adjusted_cb, self.rateadj)
- self.mouth_shape_combo.connect('changed', self.mouth_changed_cb, False)
- self.mouth_changed_cb(self.mouth_shape_combo, True)
- self.numeyesadj.connect("value_changed", self.eyes_changed_cb, False)
- self.eye_shape_combo.connect('changed', self.eyes_changed_cb, False)
- self.eyes_changed_cb(None, True)
-
- self.face.look_ahead()
-
- # say hello to the user
- presenceService = presenceservice.get_instance()
- xoOwner = presenceService.get_owner()
- self.face.say_notification(_("Hello %s. Type something.") \
- % xoOwner.props.nick)
-
- def resume_instance(self, file_path):
- cfg = cjson.decode(file(file_path, 'r').read())
-
- status = self.face.status = face.Status().deserialize(cfg['status'])
- self.voices.select(status.voice)
- self.pitchadj.value = self.face.status.pitch
- self.rateadj.value = self.face.status.rate
- self.mouth_shape_combo.select(status.mouth)
- self.eye_shape_combo.select(status.eyes[0])
- self.numeyesadj.value = len(status.eyes)
-
- self.entry.props.text = cfg['text']
- for i in cfg['history']:
- self.entrycombo.append_text(i)
-
- self.new_instance()
-
- def save_instance(self, file_path):
- cfg = { 'status' : self.face.status.serialize(),
- 'text' : self.entry.props.text,
- 'history' : map(lambda i: i[0], self.entrycombo.get_model()) }
- file(file_path, 'w').write(cjson.encode(cfg))
-
- def share_instance(self, connection, is_initiator):
- self.chat.messenger = Messenger(connection, is_initiator, self.chat)
-
- def _cursor_moved_cb(self, entry, *ignored):
- # make the eyes track the motion of the text cursor
- index = entry.props.cursor_position
- layout = entry.get_layout()
- pos = layout.get_cursor_pos(index)
- x = pos[0][0] / pango.SCALE - entry.props.scroll_offset
- y = entry.get_allocation().y
- self.face.look_at(pos=(x, y))
-
- def get_mouse(self):
- display = gtk.gdk.display_get_default()
- screen, mouseX, mouseY, modifiers = display.get_pointer()
- return mouseX, mouseY
-
- def _mouse_moved_cb(self, widget, event):
- # make the eyes track the motion of the mouse cursor
- self.face.look_at()
- self.chat.look_at()
-
- def _mouse_clicked_cb(self, widget, event):
- pass
-
- def make_voice_bar(self):
- voicebar = gtk.Toolbar()
-
- self.pitchadj = gtk.Adjustment(self.face.status.pitch, 0,
- espeak.PITCH_MAX, 1, espeak.PITCH_MAX/10, 0)
- pitchbar = gtk.HScale(self.pitchadj)
- pitchbar.set_draw_value(False)
- #pitchbar.set_inverted(True)
- pitchbar.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
- pitchbar.set_size_request(240,15)
-
- pitchbar_toolitem = ToolWidget(
- widget=pitchbar,
- label_text=_('Pitch:'))
- voicebar.insert(pitchbar_toolitem, -1)
-
- self.rateadj = gtk.Adjustment(self.face.status.rate, 0, espeak.RATE_MAX,
- 1, espeak.RATE_MAX/10, 0)
- ratebar = gtk.HScale(self.rateadj)
- ratebar.set_draw_value(False)
- #ratebar.set_inverted(True)
- ratebar.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
- ratebar.set_size_request(240,15)
-
- ratebar_toolitem = ToolWidget(
- widget=ratebar,
- label_text=_('Rate:'))
- voicebar.insert(ratebar_toolitem, -1)
-
- voicebar.show_all()
- return voicebar
-
- def pitch_adjusted_cb(self, get, data=None):
- self.face.status.pitch = get.value
- self.face.say_notification(_("pitch adjusted"))
-
- def rate_adjusted_cb(self, get, data=None):
- self.face.status.rate = get.value
- self.face.say_notification(_("rate adjusted"))
-
- def make_face_bar(self):
- facebar = gtk.Toolbar()
-
- self.mouth_shape_combo = ComboBox()
- self.mouth_shape_combo.append_item(mouth.Mouth, _("Simple"))
- self.mouth_shape_combo.append_item(waveform_mouth.WaveformMouth, _("Waveform"))
- self.mouth_shape_combo.append_item(fft_mouth.FFTMouth, _("Frequency"))
- self.mouth_shape_combo.set_active(0)
-
- mouth_shape_toolitem = ToolWidget(
- widget=self.mouth_shape_combo,
- label_text=_('Mouth:'))
- facebar.insert(mouth_shape_toolitem, -1)
-
- self.eye_shape_combo = ComboBox()
- self.eye_shape_combo.append_item(eye.Eye, _("Round"))
- self.eye_shape_combo.append_item(glasses.Glasses, _("Glasses"))
- self.eye_shape_combo.set_active(0)
-
- eye_shape_toolitem = ToolWidget(
- widget=self.eye_shape_combo,
- label_text=_('Eyes:'))
- facebar.insert(eye_shape_toolitem, -1)
-
- self.numeyesadj = gtk.Adjustment(2, 1, 5, 1, 1, 0)
- numeyesbar = gtk.HScale(self.numeyesadj)
- numeyesbar.set_draw_value(False)
- numeyesbar.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
- numeyesbar.set_size_request(240,15)
-
- numeyesbar_toolitem = ToolWidget(
- widget=numeyesbar,
- label_text=_('Eyes number:'))
- facebar.insert(numeyesbar_toolitem, -1)
-
- facebar.show_all()
- return facebar
-
- def mouth_changed_cb(self, combo, quiet):
- self.face.status.mouth = combo.props.value
- self._update_face()
-
- # this SegFaults: self.face.say(combo.get_active_text())
- if not quiet:
- self.face.say_notification(_("mouth changed"))
-
- def eyes_changed_cb(self, ignored, quiet):
- if self.numeyesadj is None:
- return
-
- self.face.status.eyes = [self.eye_shape_combo.props.value] \
- * int(self.numeyesadj.value)
- self._update_face()
-
- # this SegFaults: self.face.say(self.eye_shape_combo.get_active_text())
- if not quiet:
- self.face.say_notification(_("eyes changed"))
-
- def _update_face(self):
- self.face.update()
- self.chat.update(self.face.status)
-
- def _combo_changed_cb(self, combo):
- # when a new item is chosen, make sure the text is selected
- if not self.entry.is_focus():
- self.entry.grab_focus()
- self.entry.select_region(0,-1)
-
- def _entry_key_press_cb(self, combo, event):
- # make the up/down arrows navigate through our history
- keyname = gtk.gdk.keyval_name(event.keyval)
- if keyname == "Up":
- index = self.entrycombo.get_active()
- if index>0:
- index-=1
- self.entrycombo.set_active(index)
- self.entry.select_region(0,-1)
- return True
- elif keyname == "Down":
- index = self.entrycombo.get_active()
- if index<len(self.entrycombo.get_model())-1:
- index+=1
- self.entrycombo.set_active(index)
- self.entry.select_region(0,-1)
- return True
- return False
-
- def _entry_activate_cb(self, entry):
- # the user pressed Return, say the text and clear it out
- text = entry.props.text
- if text:
- self.face.look_ahead()
-
- # speak the text
- if self._mode == MODE_BOT:
- self.face.say(
- brain.respond(self.voices.props.value, text))
- else:
- self.face.say(text)
-
- # add this text to our history unless it is the same as the last item
- history = self.entrycombo.get_model()
- if len(history)==0 or history[-1][0] != text:
- self.entrycombo.append_text(text)
- # don't let the history get too big
- while len(history)>20:
- self.entrycombo.remove_text(0)
- # select the new item
- self.entrycombo.set_active(len(history)-1)
- # select the whole text
- entry.select_region(0,-1)
-
- def _activeCb( self, widget, pspec ):
- # only generate sound when this activity is active
- if not self.props.active:
- self.face.shut_up()
- self.chat.shut_up()
-
- def _set_voice(self, new_voice):
- try:
- self.voices.handler_block_by_func(self.__changed_voices_cb)
- self.voices.select(new_voice)
- finally:
- self.voices.handler_unblock_by_func(self.__changed_voices_cb)
-
- def __toggled_mode_type_cb(self, button, voices_model):
- if not button.props.active:
- return
-
- self._mode = MODE_TYPE
- self.chat.shut_up()
- self.face.shut_up()
- self.notebook.set_current_page(0)
-
- old_voice = self.voices.props.value
- self.voices.set_model(voices_model)
- self._set_voice(old_voice)
-
- def __toggled_mode_robot_cb(self, button, voices_model):
- if not button.props.active:
- return
-
- self._mode = MODE_BOT
- self.chat.shut_up()
- self.face.shut_up()
- self.notebook.set_current_page(0)
-
- old_voice = self.voices.props.value
- self.voices.set_model(voices_model)
-
- if not [i for i in voices_model if i[0] == old_voice]:
- new_voice = brain.get_default_voice()
- sorry = _("Sorry, I can't speak %s, let's speak %s instead.") % \
- (old_voice.friendlyname, new_voice.friendlyname)
- else:
- new_voice = old_voice
- sorry = None
-
- self._set_voice(new_voice)
-
- if not brain.load(self, self.voices.props.value, sorry):
- if sorry:
- self.face.say_notification(sorry)
-
- def __toggled_mode_chat_cb(self, button, voices_model):
- if not button.props.active:
- return
-
- self._mode = MODE_CHAT
- self.face.shut_up()
- self.notebook.set_current_page(1)
-
- old_voice = self.voices.props.value
- self.voices.set_model(voices_model)
- self._set_voice(old_voice)
-
- def __changed_voices_cb(self, combo):
- voice = combo.props.value
-
- if self._mode == MODE_BOT:
- self.face.set_voice(voice)
- brain.load(self, voice)
- else:
- self.face.set_voice(voice)
- self.face.say_notification(voice.friendlyname)
-
-
-# activate gtk threads when this module loads
-gtk.gdk.threads_init()