the savviest SAVS yet: a simpler simple audio text synchronizer

It's been over three years, apparently, since I worked on SAVS, the "Simple Audio/Verse Synchronizer" – or whatever it stands for.

The code mostly worked, but it was all over the place.

I just worked on a much cleaner version the last couple of days.

It still needs work but now requires way less from the person making the HTML markup.

One needs to:

  1. Add a CSS rule for the class "SAVS-mark" – this changes the look of the current line to be a highlight or whatever.
    • I'll eventually make this optional and just add the styling via script if no style parameters are passed by the web developer.
  2. Set the "audio" element to have an "id" value of "SAVS-player".
  3. Add the class "SAVS" for all timed-text elements with "data-SAVS-start" and "data-SAVS-stop" values (seconds).
  4. Include the SAVS JavaScript code.

The demo is here here and one can see the simpler HTML markup as well as the JavaScript that makes it work.

But because it's a cheap way for me to feel like I'm creating better content, I'll also post the code below.

I need to eat, so I'm keeping this post short – I mean simple.

function SAVS(name) {

  self = this;
  
  // Returns elements with class of "SAVS".
  _getList = function () {
    var cls = document.getElementsByClassName('SAVS');
    return cls;
  };
  
  // Adds "onclick"" attribute to elements of class "SAVS".
  _setList = function () {
    var st2 = self.st2;
    for (i = 0; i < st2.length; i++) {
      fnc = self.name + '.player.currentTime=' + st2[i].start;
      self.list[i].setAttribute('onclick', fnc)
    }
  };

  // Returns items in _getList() with start/stop properties.
  _list2dict = function () {
    var dict = [];
    var list = self.list;
    for (i = 0; i < list.length; i++) {
      start = list[i].getAttribute('data-SAVS-start');
      stop = list[i].getAttribute('data-SAVS-stop');
      dict.push({
        'start': start,
        'stop': stop
      });
    };
    return dict;
  };

  // Returns player element.
  _getPlayer = function () {
    return document.getElementById('SAVS-player');
  }
  
  // Adds "ontimeupdate" attribute to player.
  _setPlayer = function () {
    var fnc = self.name + '.setRegion(' + self.name + '.getRegion(this.currentTime))';
    self.player.setAttribute('ontimeupdate', fnc);
    return;
  };
  
  // Returns element index where "ss" (seconds) is within timed text element's start/stop times.
  self.getRegion = function (ss) {
    var st2 = self.st2
    for (i = 0; i < st2.length; i++) {
      if ((ss >= st2[i].start) && (ss < st2[i].stop)) {
        return i;
      }
    };
  };
  
  // Updates class of current and previous timed text elements.
  self.setRegion = function (node) {
    if (typeof node != 'undefined') {
      if (node != self.currentNode) {
        self.list[self.currentNode].classList.remove('SAVS-mark');
      }
      self.list[node].classList.add('SAVS-mark');
      self.currentNode = node;
    } 
    else {
      self.list[self.currentNode].classList.remove('SAVS-mark');
    }
    return;
  };
  
  // Setup.
  __init = function () {
    self.name = name;
    self.currentNode = 0;
    self.list = _getList();
    self.st2 = _list2dict();
    self.player = _getPlayer();
    _setList();
    _setPlayer();
    return;
  }
  
__init();
};

var savs = new SAVS('savs');
--------------

Related Content:

2 Comments

  1. Firat

    Hi,
    I recently launched a web app which creates and publishes "Read along" books for LibriVox recordings. Although I did not use your code, one of the earlier versions of "SAVS" was my starting point, along with another sample code from someone else. Thought you could find it interesting: https://readiance.org.

    You might also want to check out 'aeneas'. It's a Python library for automatic audio-text alignment. It has a TTS based approach, which makes it more convenient and flexible than speech recognition based forced-aligners.

    Regards,
    Firat

    Reply
    1. nitin (Post author)

      Thanks Firat. I'll definitely take a look!

      Reply

Leave a Comment

Your email address will not be published. Required fields are marked *


*