view service/speechMusic/speechMusic.py @ 215:1e94d074f642

ipv6 support Ignore-this: b6fe9c1fe232302cdd1b6469cbc8ac24
author drewp@bigasterisk.com
date Sun, 03 Jan 2016 02:27:37 -0800
parents 1132ab1ade80
children b3959142d7d8
line wrap: on
line source

#!bin/python
"""
play sounds according to POST requests.
"""
from __future__ import division
import sys, tempfile, logging, pyjade
from pyjade.ext.mako import preprocessor as mako_preprocessor
from mako.template import Template
from mako.lookup import TemplateLookup
sys.path.append("python-openal")
import openal
from twisted.internet import reactor
sys.path.append("/my/proj/csigen")
from generator import tts
import xml.etree.ElementTree as ET
from klein import Klein
from twisted.web.static import File
logging.basicConfig(level=logging.INFO,
                    format="%(created)f %(asctime)s %(levelname)s %(message)s")
log = logging.getLogger()

templates = TemplateLookup(directories=['.'],
                           preprocessor=mako_preprocessor,
                           filesystem_checks=True)

def makeSpeech(speech, fast=False):
    speechWav = tempfile.NamedTemporaryFile(suffix='.wav')

    root = ET.Element("SABLE")
    r = ET.SubElement(root, "RATE",
                      attrib=dict(SPEED="+50%" if fast else "+0%"))
    for sentence in speech.split('.'):
        div = ET.SubElement(r, "DIV")
        div.set("TYPE", "sentence")
        div.text = sentence

    speechSecs = tts(root, speechWav.name)
    return openal.Buffer(speechWav.name), speechSecs

class SoundEffects(object):
    def __init__(self):
        # for names to pass to this, see alcGetString with ALC_ALL_DEVICES_SPECIFIER
        device = openal.Device()
        self.contextlistener = device.ContextListener()

        # also '/my/music/entrance/%s.wav' then speak "Neew %s. %s" % (sensorWords[data['sensor']], data['name']),

        print "loading"
        self.buffers = {
            'leave': openal.Buffer('/my/music/entrance/leave.wav'),
            'highlight' : openal.Buffer('/my/music/snd/Oxygen/KDE-Im-Highlight-Msg-44100.wav'),
            'question' : openal.Buffer('/my/music/snd/angel_ogg/angel_question.wav'),
            'jazztrumpet': openal.Buffer('/my/music/snd/sampleswap/MELODIC SAMPLES and LOOPS/Acid Jazz Trumpet Lines/acid-jazz-trumpet-11.wav'),
            'beep1': openal.Buffer('/my/music/snd/bxfr/beep1.wav'),
            'beep2': openal.Buffer('/my/music/snd/bxfr/beep2.wav'),
        }
        print "loaded sounds"
        self.playingSources = []
        self.queued = []

    def playEffect(self, name):
        return self.playBuffer(self.buffers[name])

    def playSpeech(self, txt, preEffect=None, postEffect=None, preEffectOverlap=0):
        buf, secs = makeSpeech(txt)
        t = 0
        if preEffect:
            t += self.playEffect(preEffect)
            t -= preEffectOverlap
            
        reactor.callLater(t, self.playBuffer, buf)
        t += secs

        if postEffect:
            self.playBufferLater(t, self.buffers[postEffect])

    def playBufferLater(self, t, buf):
        self.queued.append(reactor.callLater(t, self.playBuffer, buf))
            
    def playBuffer(self, buf):
        src = self.contextlistener.get_source()
        src.buffer = buf
        src.play()

        secs = buf.size / (buf.frequency * buf.channels * buf.bits / 8)
        self.playingSources.append(src)
        reactor.callLater(secs + .1, self.done, src)
        return secs

    def done(self, src):
        try:
            self.playingSources.remove(src)
        except ValueError:
            pass

    def stopAll(self):
        while self.playingSources:
            self.playingSources.pop().stop()
        for q in self.queued:
            q.cancel()

class Server(object):
    app = Klein()
    def __init__(self, sfx):
        self.sfx = sfx

    @app.route('/static/', branch=True)
    def static(self, request):
        return File("./static")

    @app.route('/', methods=['GET'])
    def index(self, request):
        t = templates.get_template("index.jade")
        return t.render(effectNames=[
            dict(name=k, postUri='effects/%s' % k)
            for k in self.sfx.buffers.keys()])

    @app.route('/speak', methods=['POST'])
    def speak(self, request):
        self.sfx.playSpeech(request.args['msg'][0])
        return "ok"

    @app.route('/effects/<string:name>', methods=['POST'])
    def effect(self, request, name):
        self.sfx.playEffect(name)
        return "ok"

    @app.route('/stopAll', methods=['POST'])
    def stopAll(self, request):
        self.sfx.stopAll()
        return "ok"
        
sfx = SoundEffects()

server = Server(sfx)
server.app.run("::", 9049)