Just
Some Drops

Synchronizing the Audio with the Text

In this article, we are going to look how to synchronize the audio with the text. Our goal is, while the audio is playing, the said text in the audio should be highlighted in the paragraph.

For this demo, I have chosen a small audio of a quote from Henry Ford about success.

Coming together is a beginning; keeping together is progress; working together is success.

Henry Ford

And our basic HTML markup is just as simple as that audio.

<p><button id="play" class="myButton">Read to Me</button></p>
<audio id="a1" src="../audio/a01.mp3" type="audio/mpeg">HTML5 audio not supported</audio>
<blockquote>
 	<p>Coming together is a beginning; keeping together is progress; working together is success.</p>
	<p class="credit">— Henry Ford</p>
</blockquote>

To toggle the highlight, we might need to create highlight class.

.highlight {
	background: #C05151;
}

.myButton {
	background: #000000;
	border-radius: 10px;
	width: 50px;
	box-shadow: 5px 5px 5px #000000;

In order to identify the match timing with the words, we need to wrap the words with a unique id.

<blockquote>
  <p><span id="w0">Coming</span> <span id="w1">together</span>
	<span id="w2">is</span> <span id="w3">a</span> <span id="w4">beginning</span>;
	<span id="w5">keeping</span> <span id="w6">together</span> 
	<span id="w7">is</span> <span id="w8">progress</span>;
	<span id="w9">working</span> <span id="w10">together</span> 
	<span id="w11">is</span> <span id="w12">success</span>.</p>
  <p class="credit">— <span id="w13">Henry</span> <span id="w14">Ford</span></span p>
</blockquote>
			

Now comes the important part of the article, I used a tool called Audacity to get the audio timings. And arranged them in an array

var timeData = [
	{"start": "0.000", "end": "0.490", "text": "Coming"},
	{"start": "0.491", "end": "0.918", "text": "together"},
	{"start": "0.919", "end": "1.099", "text": "is"},
	{"start": "1.100", "end": "1.110", "text": "a"},
	{"start": "1.111", "end": "1.580", "text": "beginning"},
	{"start": "2.225", "end": "2.595", "text": "keeping"},
	{"start": "2.595", "end": "3.099", "text": "together"},
	{"start": "3.110", "end": "3.280", "text": "is"},
	{"start": "3.290", "end": "3.997", "text": "progress"},
	{"start": "4.127", "end": "4.427", "text": "working"},
	{"start": "4.523", "end": "4.933", "text": "together"},
	{"start": "4.943", "end": "5.073", "text": "is"},
	{"start": "5.074", "end": "5.873", "text": "success"},
	{"start": "6.944", "end": "7.390", "text": "Henry"},
	{"start": "7.543", "end": "7.909", "text": "Ford"},
];

The rest is easy. We just need to make a eventListener to the play button and another eventListener for timeupdate which calls a function to highlight the word within the span tag, when the play timing is within the range of the word.

var audio = document.getElementById('a1');
var play = document.getElementById('play');
play.addEventListener('click', function(){
	audio.play();
});
audio.addEventListener('timeupdate', function(){
	timeData.forEach(function(element, index, array) {
		if(audio.currentTime >= element.start && audio.currentTime <= element.end) {
    	 	var highlightId = 'w' + index;
    		document.getElementById(highlightId).className = 'highlight';
    		var removeHightlight = 'w' + (index - 1);
    		document.getElementById(removeHightlight).className = '';
    		}
	});
});