I'm trying to accomplish playing a sound effect multiple times; first, it is triggered by the press of the button, and then it plays twice more after, in intervals intended to be two seconds after the last.
My current (relevant) HTML:
<!-- AUDIO -->
<audio id="ring_audio" autostart="false" src="http://www.freesound.org/data/previews/352/352300_2247456-lq.mp3"></audio>
<audio id="ring_audio2" autostart="false" src="http://www.freesound.org/data/previews/352/352300_2247456-lq.mp3"></audio>
<audio id="click_audio" autostart="false" src="http://www.freesound.org/data/previews/192/192273_3509815-lq.mp3"></audio>
<div id="title_screen">
<img src="http://data.whicdn.com/images/66375886/large.gif">
<h1>Untitled.</h1>
<h2>a short adventure game</h2>
<button id="start" type="button" onclick="playClick(); fade_title(); playRing_Delay(); playRing_Stop();">Begin</button>
</div>
And my current javascript:
function playClick() {
var audio = document.getElementById("click_audio");
audio.currentTime = 0.3;
audio.play();
}
function fade_title() {
var titlescreen = document.getElementById("title_screen");
titlescreen.style.display = "none";
}
function playRing_Delay() {
setTimeout(function playRing() {
var audio = document.getElementById("ring_audio");
audio.play();
}, 5000);
setTimeout(function playRing() {
var audio = document.getElementById("ring_audio");
audio.play();
}, 7000);
}
function playRing_Stop() {
setTimeout (function playRing() {
var audio = document.getElementById("ring_audio2");
audio.play();
}, 9000);
}
Originally, I attempted to tackle this through use of a for loop and keep it contained just to one function:
function playRing_Delay() {
setTimeout(function playRing() {
var audio = document.getElementById("ring_audio");
for (i = 0; i < 4; i++) {
if i < 3 { //the first two times
audio.play(); //plays audio as normal
}
else { //the last time it plays
audio.play();
setTimeout(function stopRing() {
audio.pause();
}, 500) //stops audio after half a second
}
}
}, 5000);
}
Which, sadly, did not work, so then I attempted to repeat the first bit three times, simply increasing the number of waiting milliseconds so they'd follow in proper succession; I'm not going to paste it because essentially I just put playRing_Stop()'s contents inside of playRing_Delay()'s.
Additionally, I noticed that when I shifted the final ring's wait period (from 9000ms > 2000ms), it played, followed by the one set to 5000ms (as expected), and the second one (7000ms) didn't.
Could someone provide a solution for this - or at the very least explain to me why it happens?
Note: I purposely left out the early stopping point to the third ring in the other methods after my for loop method failed.
That happens because the #ring_audio file is 3 seconds long, and you are trying to replay it after 2 seconds. So it is still playing when you issue the 2nd play command to it.
You should set its currentTime to 0 if you want to restart it before finishing (or wait the full 3 seconds before re-running play on it)
function playRing_Delay() {
setTimeout(function playRing() {
var audio = document.getElementById("ring_audio");
audio.play();
}, 5000);
setTimeout(function playRing() {
var audio = document.getElementById("ring_audio");
audio.currentTime = 0;
audio.play();
}, 7000);
}
Related
I have a set interval and within the set interval I have a sound that needs to be played once and once only but the trouble is the sound keeps looping and doesn't stop does anyone have any idea to what I'm doing wrong here is what I have tried:
html:
<audio id="swoosh">
<source src="/resources/music/swoosh.mp3" type="audio/mpeg">
</audio>
js:
var swoosh = document.getElementById("swoosh");
setInterval(function () {
if ($('.c:contains("01")').length > 0) {
$(".links #abt").attr("href", "about.html");
swoosh.addEventListener('ended', function () {
swoosh.pause();
swoosh.currentTime = 0;
swoosh.loop = false;
}, false);
swoosh.play();
//
if ($('.c:contains("02")').length > 0) {
$(".links #work").attr("href", "work.html");
swoosh.addEventListener('ended', function () {
swoosh.pause();
swoosh.currentTime = 0;
swoosh.loop = false;
}, false);
swoosh.play();
}
}
}, 10);
The aim is to play the sound when the contents of class="c" changes so if the contents is 01 the audio should play once and then pause or stop then when it changes to 02 it should play again and then stop or pause etc etc
Thanks in advance.
I think that you're trying to do that. Store in a variable, the "last sound" reproduced and only plays a new one when it has changed. The listener over "ended" event is unnecessary because you only play once per change.
var swoosh = document.getElementById("swoosh");
var lastPlay = "00";
setInterval(function () {
var cValue = $('.c').text();
if (lastPlay != "01" && cValue.indexOf("01") >= 0) {
$(".links #abt").attr("href", "about.html");
swoosh.play();
lastPlay = "01";
}
else if (lastPlay != "02" && cValue.indexOf("02") >= 0) {
$(".links #work").attr("href", "work.html");
swoosh.play();
lastPlay = "02";
}
}, 10);
Other better way was to add a listener to the change event of the ".c" element, it avoids the "query" every 10ms. But I don't have enough code to show you.
<video id="js-video" autoplay>
<source src="./vid.mp4" type="video/mp4">
</video>
<button id="js-button">
</button>
var video = document.getElementById('js-video');
var button = document.getElementById('js-button');
var data = [
{ pauseTime: 2,
image: "./foo_1.png"
},{
pauseTime: 6,
image: "./foo_2.png"
}
];
function showOverlay() {
video.addEventListener('timeupdate', function() {
var full = parseInt(video.currentTime);
console.log(video.currentTime);
for (var i=0; i < data.length; i++) {
if (full === data[i].pauseTime) {
video.pause();
moveToNextScene();
} else {
console.log("else");
}
}
});
}
function moveToNextScene() {
button.addEventListener('click', function() {
video.play();
});
}
showOverlay();
I have a video and using the data array, I would like to pause the video at the pauseTime in the objects inside the data array and place an overlay image on top of it.
The problem I'm having is that the timeUpdate event returns a decimal number so I have to call parseInt on it but in that case the video keeps pausing at all the intervals between 2 whole numbers, eg: if I want to pause at 2 seconds, it will pause several times between 2.000001 all the way to 2.999999, but I just want it to pause once around 2.000001 (doesn't have to be exact) and no more until the next pauseTime, in this case 6.
I wrote video[0].currentTime += 1; in the if statement and it fixes this problem but then it jumps by one sec and I don't want that.
You can see what I mean here: https://jsfiddle.net/njbn0ddn/1/
I think you need a more formal way of noting completion of the event. Here we note wether we have hit that stopping point, and if we have, we move on without checking the time again. Here is the updated fiddle: https://jsfiddle.net/meqnz2vj/
var video = document.getElementById('js-video');
var button = document.getElementById('js-button');
var data = [
{ pauseTime: 2,
image: "./foo_1.png",
got_here:false
},{
pauseTime: 6,
image: "./foo_2.png",
got_here:false
}
];
function showOverlay() {
video.addEventListener('timeupdate', function() {
var full = parseInt(video.currentTime);
console.log(video.currentTime);
for (var i=0; i < data.length; i++) {
if (full === data[i].pauseTime && data[i].got_here == false) {
data[i].got_here = true;
video.pause();
moveToNextScene();
} else {
console.log("else");
}
}
});
}
//when paused, a button will appear, on closing it, the vide resumes
function moveToNextScene() {
button.addEventListener('click', function() {
video.play();
});
}
showOverlay();
am trying to assign time duration to the playlist.... but as am using onend that function is calling after completing that video, but what i want is the video should play only on its assigned time duration after that it should stops and next video should play..am using following code...
<video id="myVideo" height="100%" width="100%" autoplay onended="run();">
<source id="ss" src="video/video1.ogg" type='video/ogg'>
</video>
<script type="text/javascript">
// num_files++;
//alert(num_files);
video_count =1;
videoPlayer = document.getElementById("ss");
video=document.getElementById("myVideo");
time2= Math.round(+new Date()/1000);
function run(){
for(i=1;i<=3;i++)
{
//alert(duration[i]);
time1= Math.round(+new Date()/1000);
// alert('ctime'+time1);
dur_time=parseInt(time2,10)+parseInt(duration[i],10);
// alert('dtime'+dur_time);
video_count++;
if(time1<dur_time)
{
video_count--;
//alert(video_count);
if (video_count > num_files) video_count = 1;
videoPlayer.setAttribute("src","video/video"+video_count+".ogg");
//alert(video_count);
video.pause();
video.load();
video.play();
time1= Math.round(+new Date()/1000);
}
}
}
</script>
You need to tap into the timeupdate event which is updated when playing the video:
video.addEventListener('timeupdate', function() {
if (this.currentTime >= dur_time) {
this.pause();
/// next action
}
}, false);
You could probably achieve the same using polling (ie. setTimeout/setInterval/requestAnimationFrame) but using the event is a more clean approach and will only update on an actual time change.
Update
You can also stop a video after a certain duration this way, however, this is not "frame accurate" but can perhaps help in some extreme cases:
var seconds = 3;
setTimeout(stopVideo, seconds * 1000); /// ms
video.play();
function stopVideo() {
if (video.isPlaying) {
video.pause();
/// next action
}
}
instead of setTimeout we can use the following code and its working fine for me
video.addEventListener("timeupdate", function() {
// alert(video_count);
dur_time=parseInt(time2,10)+7;
if (this.currentTime >= 7 || time1 >= dur_time) {
this.pause();
advanceVideo();
time2= Math.round(+new Date()/1000);
}
time1= Math.round(+new Date()/1000);
}, false);
I have a play/pause button for a video player im making. Once the video has gone trough one play through, I'd like the play button to have the video start again, but it doesn't.
Here's the script im using:
function play(){
if(!media.paused && !media.ended){
media.pause();
playButton.innerHTML='Play';
window.clearInterval(updateBar);
}else{
media.play();
playButton.innerHTML='Pause';
updateBar=setInterval(update, 100)
}
}
How about structuring your function like this
function play(){
if (!media.paused) { // if currently playing (or ended?)
if (media.ended) { // if at the end
media.currentTime = 0; // go to start
} else { // else
media.pause(); // pause
playButton.innerHTML='Play';
window.clearInterval(updateBar);
return; // and end function here
}
} // then if function didn't end
media.play(); // resume playing
playButton.innerHTML='Pause';
updateBar=setInterval(update, 100);
}
The DOM Interface you're using is HTMLMediaElement.
I have a class AudioClass in javascript to play audio as below: (pseudo code)
var AudioClass = function() {
this.audioElement;
.
.
.
this.load = function(audioSource) {
this.audioElement = //create Audio, set source etc.
this.audioElement.addEventListener("loadedmetadata", function(){
//some code
});
}
this.play = function(from, to) {
if(isNaN(this.audioElement.duration)) { return; } //line 1
this.audioElement.currentTime = from/1000; //line 2 //from & to in milliseconds
setTimeout(function() {
//pause audio.
}, to-from);
}
}
And I am using the Audio as below:
/* the below lines are executed on document load. (playing background music) */
var audioInstance = new AudioClass();
audioInstance.load(audioSrc);
audioInstance.play(20000); //line 3 //20 seconds
/* the below line is used at other places whenever i need sound */
audioInstance.play(40000); //40 seconds
When I am trying to play audio at "line 3", sometimes audio is not loaded by that time, so it is throwing INVALID_STATE_ERR. DOM EXCEPTION 11 at line 2. When I checked the audio duration, it was NaN. So I added "line 1" to check whether the duration isNaN() or not, so that it doesn't try to set currentTime until the audio is loaded.
The problem here is sometimes the duration of audio is always NaN. How to fix this?
You have to create a callback to play the audio when it loads. it works whenever you call audio.play in other places because the audio is loaded by then. Here is how i suggest you do it:
var Audio = function() {
this.audioElement;
.
.
.
this.load = function(audioSource,callback) {
this.audioElement = //create Audio, set source etc.
this.audioElement.addEventListener("loadedmetadata", function(){
//some code
if(callback!=null)
callback();
});
}
this.play = function(from, to) {
if(isNaN(this.audioElement.duration)) { return; } //line 1
this.audioElement.currentTime = from/1000; //line 2 //from & to in milliseconds
setTimeout(function() {
//pause audio.
}, to-from);
}
}
then use it like this:
var audio = new Audio();
audio.load(audioSrc,function()
{
audio.play(20000);
});
an answer to a similar question shows how to preload all your audio (in the event you have others) before start using them:
Proper onload for <audio>
Play the sound in a callback registered to the loadeddata or even better, canplaythrough event of the audio element. (See javascript audio onload and similar questions.)