Cómo mostrar una transcripción de un archivo de audio en HTML5

Una transcripción es la versión escrita de un archivo de audio. Por lo general, son muy útiles para personas con deficiencias audibles. De este modo pueden disfrutar de conferencias grabadas, seminarios y demás información que haya subida en la red en forma de audio. No solo eso, las transcripciones también sirven para llevar un registro textual de eventos como entrevistas, audiencias y reuniones.

Los audios de voz de las páginas web (como los podcasts), por lo general, van acompañados de su transcripción para beneficio de aquellos que son sordos o tienen problemas auditivos. La mejor manera de crear una transcripción de un audio de voz es por medio de la interpretación manual y la grabación.

En este post, vamos a ver cómo mostrar una transcripción de un archivo de audio que se reproduzca a la par que el archivo sonoro. Para empezar tenemos que tener la transcripción lista. Para este post, he descargado un audio de ejemplo y su transcripción de voxtab.

He utilizado una lista ul de HTML para mostrar los diálogos en la página web, tal que así:

<div id="transcriptWrapper">
    <ul id="transcript">
        <li class="speaker1"><strong class="speakerName">Justin</strong>: What I am trying to say is that the appeal and the settlement are separate.</li>
        <li class="speaker2"><strong class="speakerName">Alistair</strong>: You mean that communications and announcements internal and external would be brought into the appeal process.</li>
        <li class="speaker1"><strong class="speakerName">Justin</strong>: Right, because they connect to the appeal.</li>
        ...
    </ul>
</div>

Ahora que ya tenemos la transcripción en una lista ul, lo siguiente será emborronar todo el texto. ¿Para qué? Pues para facilitar la lectura, compañeros. Menuda contradicción, ¿no? Para nada, emborronaremos todo el texto y quitaremos ese emborronamiento en la lista que se esté reproduciendo en ese mismo instante para que la lectura sea fácil. Para emborronar el li utilizaremos el filtro de CSS blur.

#transcript > li{
     -webkit-filter: blur(3px)
    filter: blur(3px);
    transition: all .8s ease;
    ...
}

En IE10 y superior puedes añadir un text-shadow para crear un efecto borroso. Puedes utilizar este código para detectar si la falta de definición en CSS se ha aplicado o no, y para cargar una hoja de estilo específica para IE si así lo necesitas. Una vez que tenemos el texto difuminado, solamente hay que darle un poco de estilo a la transcripción.

if( getComputedStyle(dialogues[0]).webkitFilter === undefined && getComputedStyle(dialogues[0]).filter === "none"){
    var headEle = document.querySelector('head'),
      linkEle = document.createElement('link');
      linkEle.type = 'text/css';
      linkEle.rel = 'stylesheet';
      linkEle.href = 'ie.css';
      headEle.appendChild(linkEle);
}

Ahora, vamos a insertar el audio en la página mediante esto.

<audio id="audio" ontimeupdate="playTranscript()" controls>
    <source src="sample.mp3" type="audio/mpeg">
    Your browser does not support the audio element.
</audio>

El evento ontimeupdate del elemento audio se dispara cada vez que currentTime se actualiza, por lo que vamos a utilizar este evento para comprobar el tiempo transcurrido del audio y poner visible el diálogo correspondiente en la transcripción. Antes que nada, vamos a crear algunas de las variables globales que vamos a necesitar.

dialogueTimings = [0,4,9,11,18,24,29,31,44,45,47];
dialogues = document.querySelectorAll('#transcript>li');
transcriptWrapper = document.querySelector('#transcriptWrapper');
audio = document.querySelector('#audio');
previousDialogueTime = -1;

dialogueTimings es un array de números que indican los segundos en los que comienza cada diálogo en la transcripción. El primer diálogo comienza en el segundo 0, el segundo en el segundo 4, y así sucesivamente. previousDialogueTime se utiliza para realizar un seguimiento de los cambios en los diálogos.

Finalmente movemos la función enganchada a ontimeupdate, denominada "playTranscript". playTranscript se dispara casi cada segundo que se reproduce el audio, así que primero tenemos que identificar qué diálogo se está reproduciendo. Supongamos que el audio está en doce y catorce, entonces reproduciremos el diálogo que comenzó a las doce y once (consulta la matriz dialogueTimings), si el tiempo actual es el 0:30 en el audio, entonces mostraremos el diálogo que empezó en el 0:29.

Por lo tanto, para encontrar el diálogo que se tiene que mostrar, lo primero que tenemos que hacer es filtrar todos los tiempos de la matriz dialogueTimings que están debajo del tiempo actual del audio. Si el tiempo actual es 0:14 vamos a filtrar los todos los números en el array que están por debajo de 14 (que son 0, 4, 9 y 11) y filtrar por el máximo. Por lo tanto, si hacemos la comprobación, veremos que es el 11 (por tanto, el diálogo debe comenzar en el 0:11).

function playTranscript(){
    var currentDialogueTime = Math.max.apply(Math, dialogueTimings.filter(function(v){return v <= audio.currentTime}));
}

Una vez calculado el currentDialogueTime, comprobamos si es lo mismo que el previousDialogueTime (es decir, si el diálogo en el audio ha cambiado o no), si no coinciden (es decir, si el diálogo ha cambiado), entonces asignamos currentDialogueTime a previousDialogueTime.

function playTranscript(){
    var currentDialogueTime = Math.max.apply(Math, dialogueTimings.filter(function(v){return v <= audio.currentTime}));
 
    if(previousDialogueTime !== currentDialogueTime) {
        previousDialogueTime = currentDialogueTime;
    }
}

Ahora vamos a utilizar el índice de currentDialogueTime en el array dialogueTimings para encontrar el diálogo en la lista de diálogos de transcripción que debe ser resaltado. Por ejemplo, si el currentDialogueTime es 11, entonces el índice de 11 del array dialogueTimings es 3, que significa que tenemos que poner visible el diálogo con índice 3 en el array de diálogos.

function playTranscript(){
    var currentDialogueTime = Math.max.apply(Math, dialogueTimings.filter(function(v){return v <= audio.currentTime}));
 
    if(previousDialogueTime !== currentDialogueTime) {
        previousDialogueTime = currentDialogueTime;
        var currentDialogue = dialogues[dialogueTimings.indexOf(currentDialogueTime)];
    }
}

Una vez que hemos encontrado el diálogo que poner visible (que es currentDialogue), hacemos scroll a transcriptWrapper (si es scrollable) hasta currentDialogue 50px abajo de la parte superior de la capa contenedora, entonces nos encontramos con el diálogo previamente seleccionado y eliminamos la clase speaking y lo añadimos a currentDialogue.

function playTranscript(){
    var currentDialogueTime = Math.max.apply(Math, dialogueTimings.filter(function(v){return v <= audio.currentTime}));
 
    if(previousDialogueTime !== currentDialogueTime) {
        previousDialogueTime = currentDialogueTime;
        var currentDialogue = dialogues[dialogueTimings.indexOf(currentDialogueTime)];
        transcriptWrapper.scrollTop  = currentDialogue.offsetTop - 50;  
        var previousDialogue = document.getElementsByClassName('speaking')[0];
        if(previousDialogue !== undefined)
            previousDialogue.className = previousDialogue.className.replace('speaking','');
        currentDialogue.className +=' speaking';
    }
}

El elemento con clase speaking se mostrará con texto no borroso.

.speaking{
  -webkit-filter: blur(0px)
  filter:blur(0px);
}

Y eso es todo, aquí está el código HTML completo y el código JS.

<div id="transcriptWrapper">
    <ul id="transcript">
        <li class="speaker1"><strong class="speakerName">Justin</strong>: What I am trying to say is that the appeal and the settlement are separate.</li>
        <li class="speaker2"><strong class="speakerName">Alistair</strong>: You mean that communications and announcements internal and external would be brought into the appeal process.</li>
        <li class="speaker1"><strong class="speakerName">Justin</strong>: Right, because they connect to the appeal.</li>
        ...
    </ul>
</div>
 
<br>
 
<audio id="audio" ontimeupdate="playTranscript()" controls>
    <source src="sample.mp3" type="audio/mpeg">
    Your browser does not support the audio element.
</audio>
 
<br>
 
<script>
dialogueTimings = [0,4,9,11,18,24,29,31,44,45,47];
dialogues = document.querySelectorAll('#transcript>li');
transcriptWrapper = document.querySelector('#transcriptWrapper');
audio = document.querySelector('#audio');
previousDialogueTime = -1;
 
function playTranscript(){
    var currentDialogueTime = Math.max.apply(Math, dialogueTimings.filter(function(v){return v <= audio.currentTime}));
 
    if(previousDialogueTime !== currentDialogueTime) {
        previousDialogueTime = currentDialogueTime;
        var currentDialogue = dialogues[dialogueTimings.indexOf(currentDialogueTime)];
        transcriptWrapper.scrollTop  = currentDialogue.offsetTop - 50;  
        var previousDialogue = document.getElementsByClassName('speaking')[0];
        if(previousDialogue !== undefined)
            previousDialogue.className = previousDialogue.className.replace('speaking','');
        currentDialogue.className +=' speaking';
    }
}
</script>

Fuente: hongkiat.com

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP
ARTÍCULO ANTERIOR