JavaScript audio object stopping in the middle of playing - javascript

In a project I'm working on, I have a JS file that should play a piece of music, and when that piece is done playing, the next one takes its place.
var soundtrack = {
0: new Audio("./music/piece1.ogg"),
2: new Audio("./music/piece2.ogg"),
1: new Audio("./music/piece3.ogg"),
3: new Audio("./music/piece4.ogg")
}
var currentTrack = 0;
function startMusic(){
soundtrack[currentTrack].play();
soundtrack[currentTrack].addEventListener("ended", function(){ nextSong()});
}
function nextSong(){
currentTrack += 1;
if(currentTrack == 4){
currentTrack = 0;
}
soundtrack[currentTrack].play();
}
$( document ).ready(function() {
setTimeout(function() { startMusic(); }, 15500);
});
My use of the object "soundtrack" may be unconventional, but there was a bug using an array so I tried this and it worked.
The first piece plays through fine, and the next one starts up fine. About maybe 10 seconds in, the playing just stops.
Any help to solve this issue would be greatly appreciated, thanks!
Note: I am aware not all pieces will play after one other, I'm waiting until this issue is fixed before continuing.

Related

I can't make a new Audio(url).play() to stop by new Audio(url).pause()

What I want to achieve: To stop a previously started sound when a new is started. What I have now: The sounds plays simultanously, none of them is stopping. The probably reason: Wrong logic statement in a line if (audio.played && audio.paused){. Before you judge me for not trying hard enough - I am trying to solve this from 3 days, I am a beginner. It should take me a few minutes, even an hour. I tried in several combinations.At the end I listed several websites which I tried and I still haven't solved it. In all answers is something similar but still I can't made a browser to chose, always only one part is executed either audio.play() or audio.pause() in the log. It works but not as I want and these logical statements are like on other informations on the forum. At the end of the message you can see all similar topics I already tried several times. I kept just as clear code as possible and I want to do it this way, in vanilla javascript because I won't deal for now with anything more complicated. An audio url is taken from modified id on click, the audios are on my disk. It works, I made some mistake in line if (audio.played && audio.paused){ Any ideas except giving up and changing a hobby?
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Timeout</title>
</head>
<script>
function playAudio3(clicked_id) {
var OriginalID = (clicked_id);
var res = OriginalID.slice(5,-1);
var audioID=res+'.mp3';
var url =audioID;
var audio = new Audio(url);
if (audio.played && audio.paused){
audio.play();
console.log('audio.play was used.');
}else {
audio.currentTime = 0
audio.pause();
console.log('audio.pause was used.');
}
}
</script>
<body>
<span id="guita2x"onclick="playAudio3(this.id);"> Guitar. </span>
<span id="piano2x" onclick="playAudio3(this.id);"> Piano. </span>
<span id="basse15x" onclick="playAudio3(this.id);"> Basse. </span>
</body>
</html>
how do i stop a sound when a key is released in JavaScript
Javascript Audio Play on click
Javascript to stop playing sound when another starts
HTML5 Audio stop function
cancel an if statement if another statement comes true
Stopping audio when another audio file is clicked using jQuery while obscuring link
https://www.w3schools.com/jsref/dom_obj_audio.asp
HTML5 Audio pause not working
Never give up, and don't change a hobby. :)
Possible solution from one hobbyist, too:
files = ['guitar', 'piano', 'bass']; // name of your files in array. You can get this array from looping through your html/spans id's too, but, this is basic logic
audios = []; //empty audios object array
for (i = 0; i < files.length; i++) {
var audioID = files[i] + '.mp3';
var url = audioID;
var audio = new Audio(url);
audios.push(audio); //place all audio objects into array
}
console.log(audios);
//now - basic logic to check which audio element to play, and to stop others
function playAudio3(clicked_id) {
for (i = 0; i < audios.length; i++) {
if (audios[i].src.includes(clicked_id)) {
audios[i].play();
} else {
audios[i].currentTime = 0
audios[i].pause();
}
}
}
So, you are creating all audio objects at the page load, and then choose which one to play. Of course, this will play all audio files from the start. If you want to keep the track of the audio progress, and play it from the last pause, you will need some additions, but, this could be the start, i hope.
OK, updated, i kept some of your code, and slightly changed some things in HTML.
Your complete code now should look like this: (HTML)
<span class='aud' id="guita1x" onclick="playAudio3(this.id);"> Guitar. </span>
<span class='aud' id="piano2x" onclick="playAudio3(this.id);"> Piano. </span>
<span class='aud' id="basse3x" onclick="playAudio3(this.id);"> Basse. </span>
Js:
spans=document.querySelectorAll('.aud');
console.log(spans);
audios = []; //empty audios object array
for (i = 0; i < spans.length; i++) {
var OriginalID = spans[i].id;
var res = OriginalID.slice(5,-1);
var audioID=res+'.mp3';
var url =audioID;
var audio = new Audio(url);
audios.push(audio); //place all audio objects into array
}
console.log(audios);
//now - basic logic to check which audio element to play, and to stop others
function playAudio3(clicked_id) {
for (i = 0; i < audios.length; i++) {
clickid=clicked_id.replace(/[A-Za-z]/g,'')+'.mp3';
if (audios[i].src.includes(clickid)) {
audios[i].play();
} else {
audios[i].currentTime = 0
audios[i].pause();
}
}
}
Now, i have just added class 'aud' to your spans, for easier targeting.
Then, i have collected id's from the spans and placed it in the audios array. (Not sure why you are slicing names/ids, you can simplify things by adding just numbers: 1, 2, 3 and so on).
NOW, this MUST work, IF
you have 3 .mp3 files in the same folder as your html/js file, called: 1.mp3, 2.mp3, 3.mp3.
if you place your javascript bellow HTML, BEFORE closing 'body' tag.

The video loop is multipling itself more than one time every time it ends

This question is using Aframe .
I have the videosphere on loop manually with addEventListener on ("end").
Code works fine until I look at the console. It gives me strange logs.
myvideo = document.querySelector("#videoSphere");
var aEntranceScene1 = document.querySelectorAll("#playButton1");
for (var i = 0; i < aEntranceScene1.length; i++) {
aEntranceScene1[i].addEventListener("click", function () {
Scene1();
});
};
function Scene1(){
myvideo.setAttribute("src", "video/AEntranceScene1.mp4");
myvideo.currentTime = 0;
myvideo.play();
console.log("playing AEntranceScene1");
Hotspots();
myvideo.addEventListener("ended", function () {
console.log("AEntranceScene1 ended");
Scene1();
});
};
function Hotspots() {
sceneIndex = 1;
document.querySelector("#DButton").emit("disappear");
setTimeout(function () {
if (sceneIndex == 1 && !myvideo.paused) {
document.querySelector("#DButton").emit("move-start");
}
}, 3000);
};
When the video plays first time. It displays the log "playing
AEntranceScene1 and when it ended, log displays "AEntranceScene1 ended" 1 time as expected.this (Attached the photo0) played 1 time
But then when the video play again. It displays the log "playing
AEntranceScene1" several times, not only add one. When it ended, log also displays several times of "AEntranceScene1 ended" this (Attached the photo1) played 2 time
This would get worst as more loop completed.This (Attached the photo2) played 3 times only
[
Can you explain to me whats happening here? and any fix to my code?
Thank you
I have found the answer myself.
Its caused by putting autoplay in the <a-assets>,
once i deleted autoplay, it works fine

Audio isn't working in JS

I am making a game that features multiple audio clips. When I ran the game locally, it worked fine, but when I hosted it on a server 2 audio clips stopped working. I am using these audio clips just like all the others, and I even tried shortening the audio clips, but nothing worked. These are the main background music to my game, so it is pretty important.
On one HTML and JS page, I have the following code.
function music(){
var snd = new Audio('Sure.mp3');
snd.volume = 0.5;
snd.play();
}
music();
setInterval(music, 115000);
And it doesn't work, even though it works locally.
var backgroundDeathMusic = new Audio('gameOver.mp3');
var backgroundMusic = new Audio('Metal.mp3');
function music(){
if(songTimer==933000){
songTimer = 0;
}
if(songTimer==0){
backgroundMusic.volume = 0.5;
backgroundMusic.play();
}
songTimer++;
}
function deathMusic(){
if(deathMusicTimer==933000){
deathMusicTimer = 0;
}
if(deathMusicTimer==0){
backgroundDeathMusic.volume = 1;
backgroundDeathMusic.play();
}
deathMusicTimer++;
}
function musicDecider(){
if(lifeCounter>0){
music();
backgroundDeathMusic.pause();
}
if(lifeCounter<=0){
deathMusic();
backgroundMusic.pause();
}
}
And on this one only the backgroundDeathMusic/gameOver.mp3 one works, despite it having the same code. Can someone tell me why, please.
Thankyou so much.

Can I optimise this js Prototype gallery to animate faster in IE?

I'm using a js image gallery on a magento site. Because Magento uses prototype, I've used prototype for this gallery; it's a simple application and I thought it unnecessary to load jQuery library as well just for this one element.
If you have a look at http://web74.justhost.com/~persia28/ in IE8 or less, the transitions between gallery slides is so slow, to the point where the text from one slide remains visible for a short time when the next slide is in place.
I know IE is rubbish with js, but I thought the extent of the slowness here is extreme, even for IE.
I don't want to load jQuery library just for this one gallery, Magento is enough of a tank as it is; so if it came to that I might opt for just putting the text in the images, not in HTML.
Anyway, would be great to hear your wisdom.
Many thanks, and here is the js code for the gallery.
var i = 0;
// The array of div names which will hold the images.
var image_slide = new Array('image-1', 'image-2', 'image-3');
// The number of images in the array.
var NumOfImages = image_slide.length;
// The time to wait before moving to the next image. Set to 3 seconds by default.
var wait = 4000;
// The Fade Function
function SwapImage(x,y) {
$(image_slide[x]).appear({ duration: 1.5 });
$(image_slide[y]).fade({duration: 1.5});
}
// the onload event handler that starts the fading.
function StartSlideShow() {
play = setInterval('Play()',wait);
$('PlayButton').hide();
$('PauseButton').appear({ duration: 0});
}
function Play() {
var imageShow, imageHide;
imageShow = i+1;
imageHide = i;
if (imageShow == NumOfImages) {
SwapImage(0,imageHide);
i = 0;
} else {
SwapImage(imageShow,imageHide);
i++;
}
}
function Stop () {
clearInterval(play);
$('PlayButton').appear({ duration: 0});
$('PauseButton').hide();
}
function GoNext() {
clearInterval(play);
$('PlayButton').appear({ duration: 0});
$('PauseButton').hide();
var imageShow, imageHide;
imageShow = i+1;
imageHide = i;
if (imageShow == NumOfImages) {
SwapImage(0,imageHide);
i = 0;
} else {
SwapImage(imageShow,imageHide);
i++;
}
}
function GoPrevious() {
clearInterval(play);
$('PlayButton').appear({ duration: 0});
$('PauseButton').hide();
var imageShow, imageHide;
imageShow = i-1;
imageHide = i;
if (i == 0) {
SwapImage(NumOfImages-1,imageHide);
i = NumOfImages-1;
} else {
SwapImage(imageShow,imageHide);
i--;
}
}
I looked at the site and it doesn't seem slow, it takes the same time to run. It looks as though the text is not changing in opacity until the end of the animation then is just being hidden. When I look with IE7 it works normally which is a clue, IE8 has a different way of making transparencies.
Magento still ships with Prototype 1.6.0 when I know that Prototype 1.6.1 fixes several IE8 bugs and Prototype 1.7 fixes some IE9 bugs too. You could try upgrading Prototype and Scriptaculous in the js/prototype/ and js/scriptaculous/ directories. I don't know if that exact problem is included which is why you should make a backup before overwriting files, if this doesn't work you will have something to rollback to.

Chrome doesn't always repeat events with JavaScript setInterval()

I want to display several images of the same size at the same position, one at a time, with a 5s interval between each change. To do so I've used jQuery.Timer, that uses setInterval() to call some show_next_image() function every 5s.
It actually does work with IE, Opera, Safara, Firefox and.. partly with Google Chrome. It's not working with Google Chrome if I open a new window and directly type my website URL: it'll show the second image and stop. And with any other situation (reload, from another link, not right after opening a new window) it'll badly work: one can see the back image before the front image is shown.
Thus I'm wondering whether I've done something wrong with my JavaScript source. What I do is I use a front and a back image. When I want to show the next image, the back img source is set to the new image, and the front image is faded out while the back one is faded in through jQuery. You can check it out at http://www.laurent-carbon.com/ (in French). The two img are identified with bg1 and bg2.
var images = ["/img/IMG_0435bg.jpg", "/img/IMG_0400bg.jpg", "/img/maisonnette 2.jpg", "/img/IMG_0383bg.jpg", "/img/IMG_0409bg.jpg", "/img/IMG_0384bg.jpg"];
var idx = 1;
var waitTime = 5000; // ms
$(document).ready(function() {
$("#bg2").hide();
$.timer(waitTime, load_next);
$.preLoadImages(images);
});
function load_next(timer) {
var toshow = images[idx];
idx++;
idx %= images.length;
back_image().attr('src', toshow);
swap_images();
}
function front_image() {
return (idx % 2 == 0) ? $("#bg1") : $("#bg2");
}
function back_image() {
return (idx % 2 == 0) ? $("#bg2") : $("#bg1");
}
function swap_images() {
back_image().fadeOut('slow');
front_image().fadeIn('slow');
}
Thanks,
Ceylo
Ok I've worked out a solution .... without the use of plugins.
Demo
http://jsfiddle.net/morrison/PvPXM/9/show
source
http://jsfiddle.net/morrison/PvPXM/9/
This approach is a lot cleaner and removes the problem I had while viewing your page in chrome: the animation getting out of sync and flashing.
The only thing you have to do in the HTML is wrap the two images in a <div id="fadeBox" style="position:relative"></div>
$(function() {
var images = [
"http://www.laurent-carbon.com/img/IMG_0435bg.jpg",
"http://www.laurent-carbon.com/img/IMG_0400bg.jpg",
"http://www.laurent-carbon.com/img/maisonnette 2.jpg",
"http://www.laurent-carbon.com/img/IMG_0383bg.jpg",
"http://www.laurent-carbon.com/img/IMG_0409bg.jpg",
"http://www.laurent-carbon.com/img/IMG_0384bg.jpg"
];
var idx = 1;
var max = images.length;
var easing = "swing";
var waitTime = 5000; // ms
var fadeTime = 2000; // ms
var fadeShow = function(fadeTime, fadeDelay) {
var $topImage = $("#fadeBox img:last");
$topImage.fadeTo(fadeDelay, 1, function() {
$topImage.fadeTo(fadeTime, 0, easing, function() {
$topImage
.fadeTo(0, 1)
.insertBefore("#fadeBox img:first")
.attr("src", images[++idx == max ? idx = 0 : idx]);
fadeShow(fadeTime, fadeDelay);
});
});
};
fadeShow(fadeTime, waitTime);
});
Hope this helps
PS thanks to Levi for cleaning the code up a bit.
Answer: http://jsfiddle.net/morrison/RxyZY/
Notes:
You are trying to reinvent the wheel. You are creating a simple slideshow. There are numerous plugins to do exactly this and much more. I used jQuery cycle in my example, which is extremely customizable.
You should wrap your stuff up in a function, creating an expression. In my example, the (function($){}(jQuery)) is what does the trick. It scopes your variables to the function, rather than the global namespace.

Categories