timesheets.js

A declarative approach for HTML Timing using SMIL Timesheets

Here is a SMIL Timing adaptation of this HTML5/Audio demo (proposed by Samuel Goldszmidt, IRCAM) — but the HTML information is synchronized with the audio track, which is precisely the goal of our project.

treble clef While the three other instruments hold a cluster of high notes, the cellist’s silent gestures interact with them, provoking a windy sonority that becomes noisier as the cellist’s gestures become more energetic.
funny music note A short interlude employing conventional playing techniques (bows are applied on the strings in the usual way, though sounds are still high and dissonant).
A rich mixture of tremolos and glissandos at various speeds in the highest register. Each part of the quartet descends progressively into the medium register: a sound colour with greater solidity emerges.
The first violin plays high notes once again, this time “flautando” i.e. with a flute-like tone (by lightly bowing across the end of the fingerboard). The other instruments follow suit until a disparate mix of “flautando” and “sul ponticello” is established and enriched by granular synthesis from the electronics.
Louder notes and groups of notes irregularly irrupt, often using a “gettato” bow stroke: the player lets the bow freely rebound against the string-once or several times in a row like a ping pong ball.
treble clef From this point onward all the preceding techniques are increasingly varied and combined. Identifying them becomes more challenging. Good luck!

controls: | |

View this demo in full page.

The four buttons above allow to quickly jump to the different musical sections. No specific JavaScript code is used for these navigation buttons: again, this is pure SMIL Timing.

Many thanks to Florence Baschet’s and the Quatuor Danel for allowing us to reproduce this extract.

HTML Markup

The markup is very similar to the one we’ve used for the previous example:

<div id="media" smil:timeContainer="excl" smil:mediaSync="audio"
     smil:first = "firstSection.click"
     smil:prev  = "prevSection.click"
     smil:next  = "nextSection.click"
     smil:last  = "lastSection.click">

  <div id="section1" smil:begin="0:00">
    <img alt="treble clef" style="float: left;" src="images/music-trebleClef.png" />
    While the three other instruments hold a cluster of high notes, the
    cellist’s silent gestures interact with them, provoking a windy sonority
    that becomes noisier as the cellist’s gestures become more energetic.
  </div>
  <div id="section2" smil:begin="0:36"> […] </div>
  <div id="section3" smil:begin="0:43"> […] </div>
  <div id="section4" smil:begin="1:09"> […] </div>
  <div id="section5" smil:begin="2:04"> […] </div>
  <div id="section6" smil:begin="3:10"> […] </div>
</div>

<div id="mediaController">
  <div id="mediaTimeline"> […] </div>
  <audio id="audioPlayer" controls autoplay preload="auto">
    <source src="media/StreicherKreis_BASCHET_extract.ogg" type="audio/ogg" />
    <source src="media/StreicherKreis_BASCHET_extract.mp3" type="audio/mpeg" />
      Your browser does not support the HTML5 &lt;audio&gt; tag,
      please upgrade to a modern browser to see this demo.
  </audio>
</div>

The main difference is that we’re using the (non-standard) mediaSync attribute to select the <audio> element as the syncMaster.

<excl> attributes: first, prev, next, last

These four attributes are used to describe a basic user interaction. Each value refer to an HTML element event:

[elementID].[event]

In the example above, these attributes are defined as follows:

<div id="media" smil:timeContainer="excl" smil:end="4:09"
     smil:first = "firstSection.click"
     smil:prev  = "prevSection.click"
     smil:next  = "nextSection.click"
     smil:last  = "lastSection.click"> 

and they point to this navigation menu:

<p class="menu">
  <button id="firstSection" title="first section">        «     </button>
  <button id="prevSection"  title="previous section"> &lt; prev </button>
  <button id="nextSection"  title="next section">     next &gt; </button>
  <button id="lastSection"  title="last section">         »     </button>
</p>

These first/prev/next/last attributes are defined in the Timesheets working draft, but they aren’t (yet?) in the SMIL Timing recommendation. They are supposed to be specific to <excl> time containers, but our implementation allows to use them in <seq> containers as well.

Note that similar time events can be used in begin and end attributes, too.

Timeline Anchors

Besides the native audio player, we've designed a visual timeline in order to access to any section directly. No specific JavaScript is involved here, it's just a set of links:

<div id="mediaTimeline">
  <a href="#section1" style="width: 87px; background-color: #2cb3ec;">
    <span>0:00 => 0:36</span>
  </a>
  <a href="#section2" style="width: 16px; background-color: #958b5f;">
    <span>0:36 => 0:43</span>
  </a>
  <a href="#section3" style="width: 62px; background-color: #efa8a8;">
    <span>0:43 => 1:09</span>
  </a>
  <a href="#section4" style="width:133px; background-color: #ed8484;">
    <span>1:09 => 2:04</span>
  </a>
  <a href="#section5" style="width:159px; background-color: #ed5a5a;">
    <span>2:04 => 3:10</span>
  </a>
  <a href="#section6" style="width:141px; background-color: #ec2c2c;">
    <span>3:10 => 4:09</span>
  </a>
</div>

Our timesheet scheduler checks for hash changes and activates the target's parent time container on the corresponding time position. This ensures your anchor is properly displayed -- both spatially and temporally.

We still had to write some specific JavaScript code to sync the play/pause buttons and the time cursor between our visual timeline and the native audio player. The code is very simple but it's specific to the HTML5 media API -- see timeline.js (~50 lines of code).

CSS Markup

We’re using transitions on CSS transformations to animate the media annotation blocks:

div#media {
  /* define a 1s transition on all properties */
  transition         : all 1s;
  -o-transition      : all 1s;
  -moz-transition    : all 1s;
  -webkit-transition : all 1s;
}
div#media div[smil=idle] {
  /* position and shape before the transition */
  opacity: 0;
  transform         : scale(0.3) translate(+200%);
  -o-transform      : scale(0.3) translate(+200%);
  -moz-transform    : scale(0.3) translate(+200%);
  -webkit-transform : scale(0.3) translate(+200%);
}
div#media div[smil=done] {
  /* position and shape after the transition */
  opacity: 0;
  transform         : scale(0.3) translate(-200%);
  -o-transform      : scale(0.3) translate(-200%);
  -moz-transform    : scale(0.3) translate(-200%);
  -webkit-transform : scale(0.3) translate(-200%);
}
div#media div[smil=active] {
  /* position and shape when active */
  opacity: 1;
  /* «transform: none;» is implicit */
}

Firefox users: these CSS transitions require Firefox 4.

Internet Explorer users: your browser doesn't support CSS transitions at all.