Jump to content

Execute code based on time in audio


MikeatW3S

Recommended Posts

I want to use an audio file to explain a table. This will mean that I will use javascript to highlight text (change color, make bold) at certain time points in the audio. There could be 100 time points in the audio file where I will need to change text and put it back again. I probably need to check the audio file time stamp every third of a second in order to make the table entry blink on and off as I am talking about it. So I don't want to spend a lot of processor time going through a bunch of if-then statements until I match the right time interval. I'd like to simply execute code at the right time. What can I do?

 

I wonder if I can add an event listener to watch for certain times in the audio. I haven't seen any reference to this on the web.

 

Maybe I can use the switch-case statement. Here I can check the currentTime() every third of a second, average that time to the nearest tenth of a second, and make a case statement only for the times (labelled by the number of tenths-of-a-second) where I need to change things. But I don't know if the switch-case statement runs through all the possible cases before getting to the case statement that matches the time. Or does the switch-case simply jump to the right case depending on an expression. If not, is there any javascript structure that does jump to code based on expression? Or can I dynamically eliminate previous case statements from the code when done with them? Your help would be appreciated. Thanks.

Edited by MikeatW3S
Link to comment
Share on other sites

This is something i was messing around with a while back

<!DOCTYPE html><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">        <meta name="viewport" id="viewport" content="target-densitydpi=high-dpi,initial-scale=1.0,user-scalable=no" />        <title>Document Title</title>        <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>        <script  type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>        <script type="text/javascript">            var t;            function myFunction() {                clearInterval(t);                var aud = document.getElementById("myAudio");                var audParent = document.getElementById("audio01");                var audPara = audParent.getElementsByTagName("p");                for (i = 0; i < audPara.length; i++)                {                    if (parseInt(audPara[i].getAttribute("data-timer")) === (parseInt(aud.currentTime) + 1))                    {                        audPara[i].className = "passageHighlight";                        break;                    }                }                t = setInterval(function() {                    myFunction();                }, 1000);            }            function endTimer()            {                clearInterval(t);                var audParent = document.getElementById("audio01");                var audPara = audParent.getElementsByTagName("p");                for (i = 0; i < audPara.length; i++)                {                    audPara[i].className = "";                }            }        </script>        <style type="text/css">            html, body {height: 100%;}            #wrapper {text-align: center; height: 150%; vertical-align: middle; display: table; width: 95%; margin: 0 auto;}            #inner_wrap {display: table-cell; vertical-align: middle;}            #audio01 {display: inline-block; text-align: left; }            #audio01 p {padding: 0 10px;}            .passageHighlight {background-color: navy; color: white;}        </style>    </head>    <body>        <audio controls onplaying="myFunction()" id="myAudio" onended="endTimer()">            <!--<source src="Opening_Remastered.mp3" type="audio/mpeg">-->            <source src="http://www.mediacollege.com/downloads/sound-effects/star-trek/tos/music/Opening_Remastered.mp3" type="audio/mpeg">            Your browser does not support the audio tag.        </audio>        <div id="wrapper">            <div id="inner_wrap">                <div id="audio01">                    <p data-timer="5">space... the final frontier</p>                    <p data-timer="9">These are the voyagers of the star ship Enterprise</p>                    <p data-timer="13">Its five year mission to explore strange new worlds</p>                    <p data-timer="18">to seek out new life and new civilisations</p>                    <p data-timer="21">To boldly go where no man has gone before</p>                </div>            </div>        </div>    </body></html>

basically the audio running time is compared with custom data-timer and when they match a highlighting class is added, and removed at end

Link to comment
Share on other sites

Maybe a hash-table will work for me

 

var foo = '35'; // where 35 is the number of tenths of a second into the audio file.

 

var cases = {}; cases['10'] = function() { alert('I am A!'); }; cases['25'] = function() { alert('I am B!'); }; cases['35'] = function() { alert('I am C!'); }if(typeof cases[foo] == 'function') { // only executes if we've defined it above cases[foo](); // I am C!}

else { // default (the fallthrough)}

 

 

Then only the code associated with a time to change text will execute, and nothing more. Of course I'd have to execute the if(typeof cases[foo] == 'function') { code every 10th of a second, or faster.

Edited by MikeatW3S
Link to comment
Share on other sites

you don't have to allow for thirds of sec to apply blink, by adding a classname you can add css3 animation to do that for you

<!DOCTYPE html><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">        <meta name="viewport" id="viewport" content="target-densitydpi=high-dpi,initial-scale=1.0,user-scalable=no" />        <title>Document Title</title>        <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>        <script  type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>        <script type="text/javascript">            var t;            var audPara;            function myFunction() {                clearInterval(t);                var aud = document.getElementById("myAudio");                var audParent = document.getElementById("audio01");                audPara = audParent.getElementsByTagName("p");                for (i = 0; i < audPara.length; i++)                {                                        if (parseInt(audPara[i].getAttribute("data-timer")) === (parseInt(aud.currentTime) + 1))                            {                                endTimer();                                audPara[i].className = "passageHighlight";                                break;                            }                   }                t = setInterval(function() {                    myFunction();                }, 1000);            }            function endTimer()            {                clearInterval(t);                var audParent = document.getElementById("audio01");                audPara = audParent.getElementsByTagName("p");                for (j = 0; j < audPara.length; j++)                {                    audPara[j].className = "";                }            }        </script>        <style type="text/css">            html, body {height: 100%;}            #wrapper {text-align: center; height: 150%; vertical-align: middle; display: table; width: 95%; margin: 0 auto;}            #inner_wrap {display: table-cell; vertical-align: middle;}            #audio01 {display: inline-block; text-align: left; }            #audio01 p {padding: 0 10px;}            .passageHighlight {background-color: navy; color: white;                               -webkit-animation-name: example; /* Chrome, Safari, Opera */                               -webkit-animation-duration: 0.666s; /* Chrome, Safari, Opera */                               -webkit-animation-iteration-count: infinite; /* Chrome, Safari, Opera */                               animation-name: example;                               animation-duration: 0.666s;                               animation-iteration-count: infinite;            }            /* Chrome, Safari, Opera */            @-webkit-keyframes example {                from {background-color: navy; color: white;}                to {background-color: lime; color: black;}            }            /* Standard syntax */            @keyframes example {                from {background-color: navy; color: white;}                to {background-color: lime; color: black;}            }            .stop{display: none;}        </style>    </head>    <body>        <audio controls onplaying="myFunction()" id="myAudio" onended="endTimer()">            <!--<source src="Opening_Remastered.mp3" type="audio/mpeg">-->            <source src="http://www.mediacollege.com/downloads/sound-effects/star-trek/tos/music/Opening_Remastered.mp3" type="audio/mpeg">            Your browser does not support the audio tag.        </audio>        <div id="wrapper">            <div id="inner_wrap">                <div id="audio01">                    <p data-timer="5">space... the final frontier</p>                    <p data-timer="9">These are the voyagers of the star ship Enterprise</p>                    <p data-timer="13">Its five year mission to explore strange new worlds</p>                    <p data-timer="18">to seek out new life and new civilisations</p>                    <p data-timer="21">To boldly go where no man has gone before</p>                    <p data-timer="25" class="stop"></p>                </div>            </div>        </div>    </body></html>
Edited by dsonesuk
Link to comment
Share on other sites

Yea, I know, alert()s would stop execution. Thanks.

 

Now I wonder, if I'd like to highlight a column and separately highlight a row, how would I refer to each separately? Can I attach a div or type or class or id to each entry in the table and then get element by column name or row name?

Edited by MikeatW3S
Link to comment
Share on other sites

table works by td cells in a row, not columns, you would have to reference a table by class or id and then i think using nth-of-type() (maybe adding additional classname representing the column to target) class would be a better option to highlight specific td cells in each tr row that would make up the column.

 

There several option available here.

Link to comment
Share on other sites

The DOM doesn't have a representation for columns, only rows. You would need to loop through all of the rows and apply the class to the cell in each one.For syncing, you can use the timeupdate event to run an event handler when the time changes, although you'll need to try to keep execution of that event handler as short as possible.https://developer.mozilla.org/en-US/docs/Web/Events/timeupdate

Link to comment
Share on other sites

table works by td cells in a row, not columns, you would have to reference a table by class or id and then i think using nth-of-type() (maybe adding additional classname representing the column to target) class would be a better option to highlight specific td cells in each tr row that would make up the column.

 

There several option available here.

So would I add a class="row1" to the first <tr> tag and then a separate class="column1", "2", "3" to each of the <td> tags in each of the 3 column, for example? Or don't the <td> and <tr> tags admit a class attribute?

Edited by MikeatW3S
Link to comment
Share on other sites

The DOM doesn't have a representation for columns, only rows. You would need to loop through all of the rows and apply the class to the cell in each one.For syncing, you can use the timeupdate event to run an event handler when the time changes, although you'll need to try to keep execution of that event handler as short as possible.https://developer.mozilla.org/en-US/docs/Web/Events/timeupdate

 

What's wrong with setting a time interval and checking the currentTime() of the audio file every so often?

Link to comment
Share on other sites

By setting parameters in function (may need to rethink this so you can change it) on what column and row to highlight, it will apply class to table which use css nth-type to highlight specific td cells to highlight column, the row just targets row index ref -1 cause index starts at 0.

<!DOCTYPE html><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">        <meta name="viewport" id="viewport" content="target-densitydpi=high-dpi,initial-scale=1.0,user-scalable=no" />        <title>Document Title</title>        <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>        <script  type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>        <script type="text/javascript">            var t;            var audPara;            var col = 0;            var row = 0;            function myFunction(rowtmp, coltmp) {                col = coltmp;                row = rowtmp;                clearInterval(t);                var aud = document.getElementById("myAudio");                var audParent = document.getElementById("audio01");                audParent.className = "col" + coltmp;                audPara = audParent.getElementsByTagName("td");                audTr = audParent.getElementsByTagName("tr");                audTr[rowtmp - 1].className = "rowcol";                switch ((parseInt(aud.currentTime) + 1)) {                    case 5:                        endTimer();                        audPara[0].className = "passageHighlight";                        break;                    case 9:                        endTimer();                        audPara[1].className = "passageHighlight";                        break;                    case 13:                        endTimer();                        audPara[2].className = "passageHighlight";                        break;                    case 18:                        endTimer();                        audPara[3].className = "passageHighlight";                        break;                    case 21:                        endTimer();                        audPara[4].className = "passageHighlight";                        break;                    case 25:                        endTimer();                        audPara[5].className = "stop xxx";                        break;                }                t = setInterval(function() {                    myFunction(row, col);                }, 1000);            }            function endTimer()            {                clearInterval(t);                var audParent = document.getElementById("audio01");                audPara = audParent.getElementsByTagName("td");                for (j = 0; j < audPara.length; j++)                {                    // if (audPara[j].className != "stop")                    //{                    audPara[j].className = "";                    //}                }            }        </script>        <style type="text/css">            html, body {height: 100%;}            #wrapper {text-align: center; height: 150%; vertical-align: middle; display: table; width: 95%; margin: 0 auto;}            #inner_wrap {display: table-cell; vertical-align: middle;}            #audio01 {display: inline-block; text-align: left; }            #audio01 p {padding: 0 10px;}            .passageHighlight {background-color: navy; color: white;                               -webkit-animation-name: example; /* Chrome, Safari, Opera */                               -webkit-animation-duration: 0.666s; /* Chrome, Safari, Opera */                               -webkit-animation-iteration-count: infinite; /* Chrome, Safari, Opera */                               animation-name: example;                               animation-duration: 0.666s;                               animation-iteration-count: infinite;            }            /* Chrome, Safari, Opera */            @-webkit-keyframes example {                from {background-color: navy; color: white;}                to {background-color: lime; color: black;}            }            /* Standard syntax */            @keyframes example {                from {background-color: navy; color: white;}                to {background-color: lime; color: black;}            }            .stop{/*display: none; background: none !important;*/}            .col1 td:nth-of-type(1), .col2 td:nth-of-type(2),  .col3 td:nth-of-type(3){ background-color: purple;}            .rowcol {background-color: orange;}        </style>    </head>    <body>        <audio controls onplaying="myFunction(1,3)" id="myAudio" onended="endTimer()">            <!--<source src="Opening_Remastered.mp3" type="audio/mpeg">-->            <source src="http://www.mediacollege.com/downloads/sound-effects/star-trek/tos/music/Opening_Remastered.mp3" type="audio/mpeg">            Your browser does not support the audio tag.        </audio>        <div id="wrapper">            <div id="inner_wrap">                <table id="audio01">                    <tr>                        <td>                            <p>space... the final frontier</p>                        </td>                        <td>                            <p>These are the voyagers of the star ship Enterprise</p>                        </td>                        <td>                            <p>Its five year mission to explore strange new worlds</p>                        </td>                    </tr>                    <tr>                        <td>                            <p>to seek out new life and new civilisations</p>                        </td>                        <td>                            <p>To boldly go where no man has gone before</p>                        </td>                        <td class="stop">                        </td>                    </tr>                </table>            </div>        </div>    </body></html>
Link to comment
Share on other sites

What's wrong with setting a time interval and checking the currentTime() of the audio file every so often?

There is no guarantee that Javascript will fire your function on regular intervals, so you may overshoot the time you're looking for. If you set up a page that fires a function every 1000ms to update a timer and let it run for a while then come back and check it, you'll realize it's slow, it doesn't fire exactly once every second. The time delay that you tell it is more of a suggestion than a rule. Most of the time it's not noticeable though, if you have a slideshow that changes pictures every 5 seconds you're not going to notice if it took 5.1 seconds to change.If you don't need things to be precise though, then using setInterval with a decent delay will be easier on the CPU. But if this is what you need:

I wonder if I can add an event listener to watch for certain times in the audio.

Then timeupdate is that event. Using timeupdate also means that if they pause the audio you don't continue to run your setInterval checks.As far as updating the page goes, there are several ideas there. One that I like is that you can create an array of objects to hold information about what needs to happen at each time change, so the objects could contain properties like timing information, element IDs or selectors, classes to add and remove, functions to execute for more detailed control, etc. In order to keep things fast, the only thing you need to do is check the first element in the array to see if it is time to apply those changes. If it is, then after doing it you shift the first element off the array, so the array will shrink as you hit the time points. You don't need to loop through that array, you only ever need to check the first element. That's kind of a destructive process though, in that it can only run once. If you need access to the previous events then after shifting the element off the array you can push it onto another array, so you end up with one array of events that have already happened and another of events that still need to happen. If they rewind or fast-forward (you can use the seeked event to handle that) then you can rebuild the array to add or remove the appropriate events.
  • Like 1
Link to comment
Share on other sites

If I put a class attribute in the <tr> or <td> tags, in order to change the color or bold font, then the color of the black table-cell boarders will also change. I don't want to change the table, just the contents of each cell. So I think I have to put a tag on just the contents of each cell. So is there a neutral HTML element that I can put inside each cell that I can attach multiple classes inside? For example, can I do this: <a class="row1 column1 cell1"></a>cell 1 contents...?

Link to comment
Share on other sites

You can use a span or a div, but using CSS to set the color or font-weight properties won't have any effect on borders, there are other properties for border styles.

Span might work, but I think div inserts a carriage return last I checked. Is it the case that <span>contents</span> won't do anything to the contents; it's "neutral", right?

Link to comment
Share on other sites

Updated

<!DOCTYPE html><html>    <head>        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">        <meta name="viewport" id="viewport" content="target-densitydpi=high-dpi,initial-scale=1.0,user-scalable=no" />        <title>Document Title</title>        <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>        <script  type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>        <script type="text/javascript">            var audTargetElement, col = 2, row = 2, audParent, aud;            window.onload = function() {                audParent = document.getElementById("AudioTable");                audParent.className = "col" + col;                audTr = audParent.getElementsByTagName("tr");                audTr[row - 1].className = "rowcol";                aud = document.getElementById("myAudio");                aud.volume = 0.2;                aud.ontimeupdate = function() {                    myFunction();                    onseeking = "myFunction()";                };                document.getElementById('AudioTable').rows[0].cells.length;            };            function myFunction() {                document.getElementById("demo").innerHTML = aud.currentTime;                /// CHANGE TARGET ELEMENT HERE                audTargetElement = audParent.getElementsByTagName("td");                var timeValue = (parseInt(aud.currentTime));                switch (true) {                    case (timeValue >= 5 && timeValue < 9):                        audTargetElement[0].className = "passageHighlight";                        break;                    case (timeValue >= 9 && timeValue < 13):                        audTargetElement[0].removeAttribute('class');                        audTargetElement[1].className = "passageHighlight";                        break;                    case (timeValue >= 13 && timeValue < 18):                        audTargetElement[1].removeAttribute('class');                        audTargetElement[2].className = "passageHighlight";                        break;                    case (timeValue >= 18 && timeValue < 21):                        audTargetElement[2].removeAttribute('class');                        audTargetElement[3].className = "passageHighlight";                        break;                    case (timeValue >= 21 && timeValue < 26):                        audTargetElement[3].removeAttribute('class');                        audTargetElement[4].className = "passageHighlight";                        break;                    case (timeValue >= 26):                        audTargetElement[4].removeAttribute('class');                        break;                    default:                        break;                }            }            function reset()            {                                for (j = 0; j < audTargetElement.length; j++)                {                    audTargetElement[j].className = "";                }            }        </script>        <style type="text/css">            html, body {height: 100%;}            #wrapper {text-align: center; height: 150%; vertical-align: middle; display: table; width: 95%; margin: 0 auto;}            #inner_wrap {display: table-cell; vertical-align: middle;}            #AudioTable {display: inline-block; text-align: left;  }            #AudioTable,  #AudioTable td {border: 1px solid #ccc;}            #AudioTable p {padding: 0 10px;}            .passageHighlight {background-color: navy; color: white;                               -webkit-animation-name: example; /* Chrome, Safari, Opera */                               -webkit-animation-duration: 0.666s; /* Chrome, Safari, Opera */                               -webkit-animation-iteration-count: infinite; /* Chrome, Safari, Opera */                               animation-name: example;                               animation-duration: 0.666s;                               animation-iteration-count: infinite;            }            /* Chrome, Safari, Opera */            @-webkit-keyframes example {                from {background-color: navy; color: white;}                to {background-color: lime; color: black;}            }            /* Standard syntax */            @keyframes example {                from {background-color: navy; color: white;}                to {background-color: lime; color: black;}            }            .col1 td:nth-of-type(1), .col2 td:nth-of-type(2),  .col3 td:nth-of-type(3){ background-color: purple;}            .rowcol {background-color: orange;}        </style>    </head>    <body>        <audio controls onplaying="myFunction()" id="myAudio" onended="reset()" onseeking="reset()">            <!--<source src="Opening_Remastered.mp3" type="audio/mpeg">-->            <source src="http://www.mediacollege.com/downloads/sound-effects/star-trek/tos/music/Opening_Remastered.mp3" type="audio/mpeg">            Your browser does not support the audio tag.        </audio>        <div id="wrapper">            <div id="inner_wrap">                <table id="AudioTable">                    <tr>                        <td>                            <p>space... the final frontier</p>                        </td>                        <td>                            <p>These are the voyagers of the star ship Enterprise</p>                        </td>                        <td>                            <p>Its five year mission to explore strange new worlds</p>                        </td>                    </tr>                    <tr>                        <td>                            <p>to seek out new life and new civilisations</p>                        </td>                        <td>                            <p>To boldly go where no man has gone before</p>                        </td>                        <td>                         </td>                    </tr>                </table>                <p>Playback position: <span id="demo"></span></p>            </div>        </div>    </body></html>

You can change audTargetElement to whatever element you chose to target (changed it from td, to p to span (removed these) and worked no problems), which apples styling to classname assigned to it as the audio timer progress, you can hit anywhere in progress bar while playing and it will automatically highlight that current range of text. You can set what col and rows to highlight by change values to your requirements.

Edited by dsonesuk
Link to comment
Share on other sites

Span might work, but I think div inserts a carriage return last I checked. Is it the case that <span>contents</span> won't do anything to the contents; it's "neutral", right?

Span elements are inline elements, div elements are block elements. That's the difference between them.
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...