#This python module is part of the Jam2Jam XO Activity, March, 2010 # #Copyright (C) 2010 Thorin Kerr & Andrew Brown # #This program 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 2 of the License, or any #later version. # #This program 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 this program; if not, write to the Free Software #Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. import gtk, gst, thread, tempfile, time, os import pygame import olpcgames from gettext import gettext as _ from sugar.graphics.toolbutton import ToolButton from sugar.graphics.toolcombobox import ToolComboBox import logging log = logging.getLogger('City run') log.setLevel(logging.DEBUG) ImagePath = os.path.dirname(os.path.abspath(__file__)) + "/City/Images" GST_PIPE = ['v4l2src', 'ffmpegcolorspace', 'pngenc'] class readScenes(object): def __init__(self, scpath): self.scpath = scpath self.scene_names = [dir for dir in os.listdir(self.scpath) if os.path.isdir(self.scpath + '/' + dir)] self.scene_data = [] for n in self.scene_names: fp = self.scpath + "/" + n mdfile = [open(fp + '/' + f) for f in os.listdir(fp) if os.path.isfile(fp + "/" + f) and f.startswith(n)] if mdfile: result = {"Name":n} defaults = {} for line in mdfile[0]: if line.startswith('#') or line.startswith('\n'): pass else: keyvals = line.split('=') if len(keyvals) == 2: key = keyvals[0].upper() val = (keyvals[1][:-1] if keyvals[1][-1] == '\n' else keyvals[1]) if key.startswith('TEMPO'): result['Tempo'] = val.replace(' ','') elif key.startswith('KEY'): result['Key'] = val.replace(' ','') elif key.startswith('MODE'): result['Mode'] = val.replace(' ','') else: pass else: raise IOError, "Bad Scene Meta Data file: %s" %keyvals result['Defaults'] = {} self.scene_data.append(result) else: raise IOError, "Can't find Meta Data file in %s Scene" %n def scene_instruct(self, name): "returns a list of strings suitable to give to a ScenePlayer object for creating a scene" for scd in self.scene_data: if scd['Name'] == name: collected = [name] for k in ['Key', 'Mode', 'Tempo', 'Defaults']: try: collected.append(str(scd[k])) except KeyError: collected.append('None') return collected def get_scene_list(self): "returns a list of scene strings for the toolbar, with City as the default" ordered_names = self.scene_names[:] if 'City' in ordered_names: ordered_names.insert(0,ordered_names.pop(ordered_names.index('City'))) return [self.scene_instruct(s) for s in ordered_names] class CameraSnap(object): """A class representing the OLPC camera.""" def __init__(self): log.info("CameraSnap init") snap_file, self.snap_path = tempfile.mkstemp(suffix = '.png') pipe = GST_PIPE + ['filesink location=%s' % self.snap_path] self.pipe = gst.parse_launch('!'.join(pipe)) self.bus = self.pipe.get_bus() log.info("tempfile is %s " %self.snap_path) def Snap(self): """Take a snapshot.""" log.info("about to set pipe state to PLAY") self.pipe.set_state(gst.STATE_PLAYING) log.info("about to poll") thread.start_new_thread(self.bus.poll, (gst.MESSAGE_EOS, -1)) for i in xrange(60): time.sleep(0.18) if os.path.getsize(self.snap_path) > 0: break else: raise IOError, "Error writing camera snap to file" return self.snap_path def Stop(self): self.pipe.set_state(gst.STATE_NULL) class Jam2JamToolBar(gtk.Toolbar): def __init__(self, activity): gtk.Toolbar.__init__(self) self.activity = activity self.parameters = ['Density', 'Pitch', 'Length', 'Timbre', 'Volume'] # no tempo here. scene_stuff = readScenes(self.activity._ScenePath) self.scenes = scene_stuff.get_scene_list() print "SCENE DATA IS ", self.scenes #self.scenes = [['City', 'A', 'minor pentatonic'], ['City', 'G#', 'major']] #this data needs to be obtained from directories self.play_pause_state = 'Playing' self.scene_init = True # Separator separator = gtk.SeparatorToolItem() separator.set_draw(True) self.insert(separator, -1) #Horizontal Parameter control combobox self._add_widget(gtk.Label(_('Horizontal:'))) self._Hparameter_combo = ToolComboBox() for i, f in enumerate(self.parameters): self._Hparameter_combo.combo.append_item(i, f) self._Hparameter_combo.combo.connect('changed', self._Hparameter_change_cb) self._add_widget(self._Hparameter_combo) self._Hparameter_combo.combo.set_active(0) # Separator separator = gtk.SeparatorToolItem() separator.set_draw(True) separator.show() self.insert(separator, -1) #Vertical Parameter control combobox self._add_widget(gtk.Label(_('Vertical:'))) self._Vparameter_combo = ToolComboBox() for j, k in enumerate(self.parameters): self._Vparameter_combo.combo.append_item(j, k) self._Vparameter_combo.combo.connect('changed', self._Vparameter_change_cb) self._add_widget(self._Vparameter_combo) self._Vparameter_combo.combo.set_active(1) # Separator separator = gtk.SeparatorToolItem() separator.set_draw(True) separator.show() self.insert(separator, -1) #Scene Selection control combobox self._add_widget(gtk.Label(_('Scene:'))) self._Scene_combo = ToolComboBox() for l, m in enumerate(self.scenes): self._Scene_combo.combo.append_item(l, m[0]) self._Scene_combo.combo.connect('changed', self._Scene_change_cb) self._add_widget(self._Scene_combo) #ought to do this safely somehow. self._Scene_combo.combo.set_active(0) self.scene_init = False # Separator separator = gtk.SeparatorToolItem() separator.set_draw(True) separator.show() self.insert(separator, -1) #Camera Button self.camera_ready = True camera_icon = ImagePath + "/camera-external.svg" camera_busy_icon = ImagePath + "/camera-busy.svg" self.camera_image, self.camera_busy_image = gtk.Image(), gtk.Image() self.camera_image.set_from_file(camera_icon) self.camera_busy_image.set_from_file(camera_busy_icon) self.camera_image.show() #camera_busy_image.show() self._cameraButton = ToolButton() self._cameraButton.set_icon_widget(self.camera_image) self._cameraButton.connect('clicked', self._cameraSnap_cb) self._cameraButton.set_tooltip(_('Snapshot')) self.insert(self._cameraButton, -1) self._cameraButton.show() # Separator separator = gtk.SeparatorToolItem() separator.set_draw(True) separator.show() self.insert(separator, -1) #Play/Pause Button pause_icon = ImagePath + "/media-playback-pause.svg" play_icon = ImagePath + "/media-playback-start.svg" self.pause_image = gtk.Image() self.pause_image.set_from_file(pause_icon) self.play_image = gtk.Image() self.play_image.set_from_file(play_icon) self._pauseButton = ToolButton() self._pauseButton.connect('clicked', self._pause_cb) self.pause_image.show() self._pauseButton.set_icon_widget(self.pause_image) self._pauseButton.set_tooltip(_('Pause')) #self._toggleplay_pause() self.insert(self._pauseButton, -1) self._pauseButton.show() # Separator separator = gtk.SeparatorToolItem() separator.set_draw(True) separator.show() self.insert(separator, -1) def _add_widget(self, widget, expand=False): tool_item = gtk.ToolItem() tool_item.set_expand(expand) tool_item.add(widget) widget.show() self.insert(tool_item, -1) tool_item.show() def _toggleplay_pause(self): if self.play_pause_state == "Playing": self.activity.jamScene.music_player.pause() self.play_image.show() self._pauseButton.set_icon_widget(self.play_image) self._pauseButton.set_tooltip(_('Play')) self.play_pause_state = "Paused" else: self.activity.jamScene.music_player.resume() self.pause_image.show() self._pauseButton.set_icon_widget(self.pause_image) self._pauseButton.set_tooltip(_('Pause')) self.play_pause_state = "Playing" try: self.activity._pgc.grab_focus() except AttributeError: pass def _show_busy_camera(self): self.camera_ready = False self.camera_busy_image.show() self._cameraButton.set_icon_widget(self.camera_busy_image) self._cameraButton.set_tooltip(_('Please wait...')) def _show_active_camera(self): self.camera_image.show() self._cameraButton.set_icon_widget(self.camera_image) self._cameraButton.set_tooltip(_('Snap')) self.camera_ready = True def _Hparameter_change_cb(self, widget): param = "Parameter|Horizontal|" + self.parameters[self._Hparameter_combo.combo.get_active()] olpcgames.eventwrap.post(olpcgames.eventwrap.Event(pygame.USEREVENT, action=param)) try: self.activity._pgc.grab_focus() except AttributeError: pass def _Vparameter_change_cb(self, widget): param = "Parameter|Vertical|" + self.parameters[self._Vparameter_combo.combo.get_active()] olpcgames.eventwrap.post(olpcgames.eventwrap.Event(pygame.USEREVENT, action=param)) try: self.activity._pgc.grab_focus() except AttributeError: pass def _Scene_change_cb(self, widget): if self.scene_init: pass else: selection = self.scenes[self._Scene_combo.combo.get_active()] scene = "Reload|" + '|'.join(map(lambda x: str(x), selection)) olpcgames.eventwrap.post(olpcgames.eventwrap.Event(pygame.USEREVENT, action=scene)) try: self.activity._pgc.grab_focus() except AttributeError: pass ### functions to assist calls from pygame def deactivate_scene_change(self): self._Scene_combo.set_sensitive(False) def reactivate_scene_change(self): self._Scene_combo.set_sensitive(True) def set_horizontal_parameter(self, param): ndx = self.parameters.index(param) self._Hparameter_combo.combo.set_active(ndx) def set_vertical_parameter(self, param): ndx = self.parameters.index(param) self._Vparameter_combo.combo.set_active(ndx) def _cameraSnap_cb(self, widget): "Here I could wrap a camera event..." def snaptime(): snap = CameraSnap() self.activity.cameras_loaded.append(snap) picpath = snap.Snap() self.activity.load_image(picpath) snap.Stop() self._show_active_camera() self.activity._pgc.grab_focus() if self.camera_ready: self._show_busy_camera() thread.start_new_thread(snaptime, ()) else: log.info('Ignoring request to use camera, as camera is currently busy') def _pause_cb(self, widget): self._toggleplay_pause() log.info("Play/Pause Button pressed")