# HG changeset patch # User Simon Cross # Date 1282653172 -7200 # Node ID 66898d81024782dbda1d3ff858df5f4adbc5cc13 # Parent ab11689aec3625bcba7f03d562c7ed3434c3850b Add hackish speech support (run regen-speech.py to generate files -- needs espeak and oggenc). diff -r ab11689aec36 -r 66898d810247 gamelib/scenes/cryo.py --- a/gamelib/scenes/cryo.py Tue Aug 24 14:17:09 2010 +0200 +++ b/gamelib/scenes/cryo.py Tue Aug 24 14:32:52 2010 +0200 @@ -5,6 +5,7 @@ from gamelib.state import Scene, Item, Thing, Result, \ InteractImage, InteractNoImage, InteractRectUnion, \ InteractAnimated +from gamelib import speech class Cryo(Scene): @@ -84,12 +85,21 @@ 'door': "shut", } + SPEECH = [ + "Sadly, this isn't that sort of game.", + "Your valiant efforts are foiled by the Evil Game Designer.", + "The door resists. Try something else, perhaps?", + "You bang on the door with the titanium femur. It makes a clanging sound.", + ] + def interact_with_titanium_leg(self, item): if self.get_data('door') == "ajar": self.open_door() return Result("You wedge the titanium femur into the chain and twist. With a satisfying *snap*, the chain breaks and the door opens.") else: - return Result("You bang on the door with the titanium femur. It makes a clanging sound.") + text = "You bang on the door with the titanium femur. It makes a clanging sound." + speech.say(self.name, text) + return Result(text) def interact_without(self): if self.get_data('door') == "shut": diff -r ab11689aec36 -r 66898d810247 gamelib/speech.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gamelib/speech.py Tue Aug 24 14:32:52 2010 +0200 @@ -0,0 +1,46 @@ +# speech.py +# Copyright Boomslang team, 2010 (see COPYING File) +# Speech playing and cache + +import re + +from sound import get_sound + + +# cache of string -> sound object mappings +_SPEECH_CACHE = {} + +# characters not to allow in filenames +_REPLACE_RE = re.compile(r"[^a-z0-9-]+") + + +class SpeechError(RuntimeError): + pass + + +def get_filename(key, text): + """Simplify text to filename.""" + filename = "%s-%s" % (key, text) + filename = filename.lower() + filename = _REPLACE_RE.sub("_", filename) + filename = filename[:30] + filename = "%s.ogg" % filename + return filename + + +def get_speech(thing_name, text): + """Load a sound object from the cache.""" + key = (thing_name, text) + if key in _SPEECH_CACHE: + return _SPEECH_CACHE[key] + filename = get_filename(thing_name, text) + _SPEECH_CACHE[key] = sound = get_sound("speech", filename) + print filename, sound + return sound + + +def say(thing_name, text): + """Play text as speech.""" + sound = get_speech(thing_name, text) + if sound is not None: + sound.play() diff -r ab11689aec36 -r 66898d810247 scripts/regen-speech.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/regen-speech.py Tue Aug 24 14:32:52 2010 +0200 @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +import pygame +import subprocess +import os + +from gamelib.state import initial_state +from gamelib import speech + +from albow.resource import resource_path + +from pygame.locals import SWSURFACE +from gamelib.constants import SCREEN + +# We need this stuff set up so we can load images and whatnot. +pygame.display.init() +pygame.display.set_mode(SCREEN, SWSURFACE) + + +def espeak(text, filename, voice="en-sc"): + """Call espeak. Use espeak --voices for list of voices.""" + tmpfile = "%s.wav" % filename + stdout = open(tmpfile, "wb") + subprocess.call(["espeak", "--stdout", "-v", voice, text], stdout=stdout) + print ["oggenc", tmpfile, "-o", filename] + subprocess.call(["oggenc", tmpfile, "-o", filename]) + os.remove(tmpfile) + + +def main(): + state = initial_state() + for scene in state.scenes.values(): + for thing in scene.things.values(): + texts = getattr(thing, "SPEECH", None) + if texts is None: + continue + for text in texts: + filename = speech.get_filename(thing.name, text) + filename = resource_path("sounds", "speech", filename) + print "[%s: %s] -> %s" % (thing.name, text[:30], filename) + espeak(text, filename) + + +if __name__ == "__main__": + main()