changeset 109:66898d810247

Add hackish speech support (run regen-speech.py to generate files -- needs espeak and oggenc).
author Simon Cross <simon@simonx>
date Tue, 24 Aug 2010 14:32:52 +0200
parents ab11689aec36
children 545dee3bd8e9
files gamelib/scenes/cryo.py gamelib/speech.py scripts/regen-speech.py
diffstat 3 files changed, 102 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- 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":
--- /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()
--- /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()