mindtrove Collecting ideas since 1980

19Feb/102

HTML5 audio caching

One of my latest coding endeavors is a text-to-speech interface for JavaScript using HTML5 <audio> elements to output synthesized speech from a server. To reduce the latency between a speech request and actual speech output, I'm using various levels of caching. One of these is the regular browser disk cache based on HTTP headers.

It turns out that browser caching behavior for <audio> data varies wildly among browsers. The following table shows the HTML5 <audio> caching behavior of various browsers. I tested all of them on OS X 10.6 with the standard Mac Apache server hosting all of the tested audio files.

Browser <audio> Behavior
Firefox 3.6 Respects cache headers for the sound data. Only contacts the server when the cache item expires. <audio> elements pointing to the same src reuse the cache data.
Chrome 5.0.322.2 Contacts the server on every load(). When it receives a 304 response, does not refetch content.*
Safari 4.0.4 Contacts the server to fetch first two bytes of the audio file on every load(). Receives a 206 response with partial content. Fetches the additional bytes from the file. Receives another 206 response with the partial content. Performs another fetch and receives a 304 response with no data. Continues to alternate between fetches that receive 206 partial data responses and 304 not modified responses. Nothing appears to get cached.
Webkit r54921 Same behavior as Safari 4.0.4.

* Though not cache related, audio output in Chrome is often clipped before the end of the actual audio data. When this occurs, Chrome fires the onended event even before the audible output finishes.

Except for Firefox 3.6, all of these browsers seem to exhibit pretty terrible caching behavior when it comes to audio. I've reported bugs where I thought appropriate, but maybe I'm missing something. Am I supposed to include additional headers in the server-side response? Or maybe I'm glossing over some key part of the <audio> API? If so, please let me know. If not, yikes: <audio> support has definite room for improvement.

30Nov/093

Ken Burns Effect in Dojo

I saw a reference to the jQuery CrossSlide plug-in many moons ago. For some dojo.anim practice, I decided to implement its Ken Burns effect in a reusable Dojo widget a few days later. The code then collected dust in my Dropbox until today when I finally got around to sharing it.

Below is an example instance of the widget panning, zooming, and crossfading three images. The BSD code for the widget is in KenBurns.js. The code for this particular demo can be seen by viewing the source of kenburns-demo.html.

I didn't take the time to comment this little experiment. If you'd like more info about how to use it or how it works, drop me a comment.

28Nov/090

Spaceship! code at GitHub

I cloned the code for Spaceship! at GitHub to facilitate easier development by anyone interested. I'll push any future improvements I make there and consider my personal subversion repository dead.

http://github.com/parente/spaceship

22Nov/090

pyttsx

pyttsx is a cross-platform text-to-speech package for Python. It has a simple API for producing speech, setting some basic engine properties, and getting start/stop/word callbacks. pyttsx currently supports SAPI5, NSSpeechSynthesizer, and espeak, but it can be extended to support other engines and libraries.

The project BSD licensed and hosted on Launchpad. PyPI tracks downloads for the latest stable version and documentation.

Tagged as: , , No Comments
28Aug/090

GtkBuilder/Glade on IronPython

Thanks to Stephane for his answer to my query about using GtkBuilder in IronPython. It turns out his Gtk#Beans package provides the magic sauce that is currently missing from gtk# trunk the current stable release.

For completeness, here's the code I sent him that accomplishes the same thing using the older Glade.XML object for those that are interested. It answers a long standing mailing list question about using Glade.XML.Autoconnect in IronPython.

import clr
clr.AddReference('gtk-sharp')
clr.AddReference('glade-sharp')
import Gtk
import Glade
 
def PyGladeAutoconnect(gxml, target):
    def _connect(handler_name, event_obj, signal_name, *args):
        name = ''.join([frag.title() for frag in signal_name.split('_')])
        event = getattr(event_obj, name)
        event += getattr(target, handler_name)
 
    # add all widgets
    for widget in gxml.GetWidgetPrefix(''):
        setattr(target, gxml.GetWidgetName(widget), widget)
    # connect all signals
    gxml.SignalAutoconnectFull(_connect)
 
class Application:
    def __init__(self):
        gxml = Glade.XML("test.glade", "window1", None)
        PyGladeAutoconnect(gxml, self)
        # window1 comes from glade file
        self.window1.ShowAll()
 
    def onWindowDelete(self, o, args):
        # connected via glade file definition
        Gtk.Application.Quit()
 
Gtk.Application.Init()
app = Application()
Gtk.Application.Run()
Tagged as: , , No Comments