HTML5 audio won't play sometimes - javascript

In my application, I am creating 10 audio object and I store them in a browser variable. Based on the scenario, I will pick one of them and will assign it to one global variable. Then I play that sound. After some time I will stop and clear that audio from the global variable.
I am verifying the readystate whenever I play the sound. I capture Play & Pause events.
The problem is that sometimes the sound is not audible but play & pause events are still fired. I am not able to reproduce it all the times (it happens randomly).
Please let me know if anyone faced this kind of issue.
function Sound(){}
try
{
if(new Audio().canPlayType("audio/wav") != "" && new Audio().canPlayType("audio/wav") != "no" ){
Sound.extn="wav";//No I18N
}
else{
Sound.extn="mp3";//No I18N
}
}
catch (e) {
}
Sound.init=function(soundsobj)
{
for (var tunename in soundsobj)
{
var audioobj = new Audio(soundsobj[tunename]);
audioobj.setAttribute("autobuffer", "true");
audioobj.addEventListener('loadeddata', function() {
Sound.cache[tunename]=this;
});
audioobj.addEventListener('loadedmetadata', function() {
this.currentTime = 0;
});
Sound._SOUND_PLAYER.addEventListener( "play", function(){console.log(this.readyState);}, false);
Sound._SOUND_PLAYER.addEventListener( "pause", function(){console.log(this.readyState);}, false);
}
}
Sound.playTune=function(tunename,duration)
{
if(Sound.cache[tunename])
{
var cachedsound = Sound.cache[tunename];
if(cachedsound.readyState == 4)
{
cachedsound.currentTime = 0;
Sound._SOUND_PLAYER = cachedsound;
Sound.play(duration);
}
else
{
delete Sound.cache[tunename];
var audioobj = new Audio(soundsobj[tunename]);
audioobj.setAttribute("autobuffer", "true");
audioobj.addEventListener('loadeddata', function() {
Sound.cache[tunename]=this;
Sound._SOUND_PLAYER = this;
Sound.play(duration);
});
}
}
}
Sound.play = function(duration)
{
Sound._SOUND_PLAYER.loop=true;
Sound._SOUND_PLAYER.play();
clearTimeout(Sound.cleartimer);
Sound.cleartimer = setTimeout(function(){Sound.stop()},duration*1000);
}
Sound.stop=function()
{
try
{
if(Sound._SOUND_PLAYER)
{
Sound._SOUND_PLAYER.pause();
}
Sound._SOUND_PLAYER = undefined;
}
catch(e){}
}

Related

Drum machine <audio> lag

I'm putting together a drum machine/sequencer and while the main functionality of the sequencer works fine, the audio that I've embedded in each drum cell does have a noticeable lag when the sequencer is first played. It seems to correct itself after the first beat and everything plays as normal, until other sounds are added to the pattern.
I have three rows of table cells, with each row representing a different drum sound. When the user constructs a drum pattern using all the sounds available, the loop eventually seems to go out of sync, with some sounds playing a fraction of a second later than others, but later corrects itself. My main concern is that the playback of the samples is inconsistent.
I've embedded the tags in elements with a preload attribute set to auto.
<table class="pad">
<tbody>
<tr>
<td class="kick sounds">
<audio preload="auto" src="https://raw.githubusercontent.com/wesbos/JavaScript30/master/01%20-%20JavaScript%20Drum%20Kit/sounds/kick.wav"></audio>
</td>
</tr>
</tbody>
</table>
So each there are 8 table cells to each row and each cell has the same format as above (with an element embedded). Admittedly, I can imagine that the way I've structured this is quite inefficient and that using the web audio API would work better, but I've yet to learn APIs. Is there something I can do in JS that can make the playback of these audio samples quicker?
EDIT: Here is the sequencer code. It cycles through each element and and checks if there is a cell selected. If so, that element's audio file is played. If not, it skips over to the next column.
class Sequencer {
playButton = btn;
clearButton = clear;
sounds = Array.from(sounds);
kicks = Array.from(kicks);
hihats = Array.from(hihats);
snares = Array.from(snares);
currentBeatIndexKick = 0;
currentBeatIndexHiHat = 0;
currentBeatIndexSnare = 0;
isPlaying = false;
constructor(msPerBeat) {
this.msPerBeat = msPerBeat;
this.playButton.addEventListener('click', () => this.toggleStartStop())
this.clearButton.addEventListener('click', () => this.clear())
this.sounds.forEach(sound => {
sound.addEventListener('click', e => {
if (((e.target.classList.contains('kick')) || (e.target.classList.contains('hihat')) || (e.target.classList.contains('snare'))) && !e.target.classList.contains('selected')) {
e.target.classList.add('selected');
} else {
e.target.classList.remove('selected');
}
})
})
}
toggleStartStop() {
if (this.isPlaying) {
this.stop();
} else {
this.start();
}
}
clear() {
this.kicks.forEach(kick => {
if (kick.classList.contains('selected')) {
kick.classList.remove('selected');
}
});
hihats.forEach(hihat => {
if (hihat.classList.contains('selected')) {
hihat.classList.remove('selected');
}
});
snares.forEach(snare => {
if (snare.classList.contains('selected')) {
snare.classList.remove('selected');
}
});
this.stop();
console.clear();
}
stop() {
this.isPlaying = false;
this.currentBeatIndexKick = 0;
this.currentBeatIndexHiHat = 0;
this.currentBeatIndexSnare = 0;
this.playButton.innerText = 'Play';
}
start() {
this.isPlaying = true;
this.playCurrentNoteAndSetTimeoutKick() // kicks
this.playCurrentNoteAndSetTimeoutHiHats() // hihats
this.playCurrentNoteAndSetTimeoutSnares() // snares
this.playButton.innerText = 'Stop';
}
playCurrentNoteAndSetTimeoutKick() {
if (this.isPlaying && this.kicks[this.currentBeatIndexKick].classList.contains('selected')) {
this.kicks[this.currentBeatIndexKick].childNodes[1].play();
setTimeout(() => {
this.toNextBeatKicks();
this.playCurrentNoteAndSetTimeoutKick();
}, this.msPerBeat)
}
if (this.isPlaying && !this.kicks[this.currentBeatIndexKick].classList.contains('selected'))
setTimeout(() => {
this.toNextBeatKicks();
this.playCurrentNoteAndSetTimeoutKick();
}, this.msPerBeat)
}
playCurrentNoteAndSetTimeoutHiHats() {
if (this.isPlaying && this.hihats[this.currentBeatIndexHiHat].classList.contains('selected')) {
this.hihats[this.currentBeatIndexHiHat].childNodes[1].play();
setTimeout(() => {
this.toNextBeatHiHats();
this.playCurrentNoteAndSetTimeoutHiHats();
}, this.msPerBeat)
}
if (this.isPlaying && !this.hihats[this.currentBeatIndexHiHat].classList.contains('selected'))
setTimeout(() => {
this.toNextBeatHiHats();
this.playCurrentNoteAndSetTimeoutHiHats();
}, this.msPerBeat)
}
playCurrentNoteAndSetTimeoutSnares() {
if (this.isPlaying && this.snares[this.currentBeatIndexSnare].classList.contains('selected')) {
this.snares[this.currentBeatIndexSnare].childNodes[1].play();
setTimeout(() => {
this.toNextBeatSnares();
this.playCurrentNoteAndSetTimeoutSnares();
}, this.msPerBeat)
}
if (this.isPlaying && !this.snares[this.currentBeatIndexSnare].classList.contains('selected'))
setTimeout(() => {
this.toNextBeatSnares();
this.playCurrentNoteAndSetTimeoutSnares();
}, this.msPerBeat)
}
toNextBeatKicks() {
this.currentBeatIndexKick = ++this.currentBeatIndexKick % this.kicks.length;
}
toNextBeatHiHats() {
this.currentBeatIndexHiHat = ++this.currentBeatIndexHiHat % this.hihats.length;
}
toNextBeatSnares() {
this.currentBeatIndexSnare = ++this.currentBeatIndexSnare % this.snares.length;
}
}
const sequencer = new Sequencer(213)
I think what you might have to do is to play the audio file programmatically. It's kind of hard to understand how your sequencer works without giving us more access to your code, the way I would approach this is by programmatically playing the audio file once the user has selected the sequence. I would assign a variable to play once the steps are selected on your sequencer.
var audio = new Audio('audio_file.mp3');
audio.play();
audio.play would be called on the sequence. Not sure if this helps but that's part of the api I think you were referring to.

Counter gets incremented twice

I am writing a simple JavaScript game in which the user clicks on a div that plays sounds and if they guess the animal sound correct, a counter keeps track of their score and increments.
It works, but if the same sound is played again and the user guesses it increments the counter with two not one and sometimes even by three and I can't figure out why and how to fix it, here is my HTML:
<div id="counter">Score:<span id="counter-score"> 0</span> </div>
and here is the JavaScript code:
var sounds = [
{
animalType: 'horse',
sound: new Audio('../sounds/Horse-neigh.mp3')
},
{
animalType: 'bear',
sound: new Audio('../sounds/grizzlybear.mp3')
},
{
animalType: 'goat',
sound: new Audio('../sounds/Goat-noise.mp3'),
}
];
var player = document.getElementById('player');
var enteredWord = document.getElementById('entered-word');
var counter = document.getElementById('counter-score');
startGame();
function startGame() {
player.addEventListener('click', function() {
var sound = sounds[Math.floor(Math.random() * sounds.length)];
var currentSound = sound.animalType;
sound['sound'].play();
enteredWord.addEventListener('keydown', function() {
if (event.key === 'Enter') {
if (enteredWord.value === currentSound) {
counter.textContent++;
}
} else {
}
});
});
}
Why does it happen like that?
I tried using the += operator but it gives the same result.
As #Ibu said in comments, each time the click event occur, a new event listener is added to keydown event.
You should extract the enteredWord.addEventListener part outside of player.addEventListener callback, like so:
function startGame() {
var currentSound;
player.addEventListener('click', function() {
var sound = sounds[Math.floor(Math.random()*sounds.length)];
currentSound = sound.animalType;
sound['sound'].play();
})
enteredWord.addEventListener('keydown', function() {
if(event.key === 'Enter') {
if(enteredWord.value === currentSound) {
counter.textContent ++;
}
}
})
}
Hi can you replace your code with this one, I think the key-down event is executing twice so you are getting this issue.
enteredWord.addEventListener('keydown', function(e) {
if( (e.keyCode ==13) && (enteredWord.value === currentSound)){
e.stopImmediatePropagation();
counter.textContent ++;
}
})

Reload a javascript after jetpack infnity scroll load

i hav a javascript for autoplay a youtube a javascript ist in file1.js and Jetpack infninity scroll file2.js the file 1 work only in the posts thej ar not from infinity scroll and at the posts thej ar loaded from jetpack infinity scroll don't work i tray a lot of posibilitys i tray to load the javascript with infnity scroll agen to the header but thets dont work to replace the js at the header thets wont work i don't know what can i do more. i nead a stacoverflow people help i am sory my english is not so good and i am new in javascript world
FILE1
window.onload = function ani2() {
var LoadVideo = function (player_id) {
var Program = {
Init: function () {
this.NewPlayer();
this.EventHandler();
},
NewPlayer: function () {
var _this = this;
this.Player = new YT.Player(player_id, {
events: {
'onStateChange': onPlayerStateChange,
}
});
_this.Player.$element = $('#' + player_id);
}
}
}
}
FILE 2
thets the file from wher play the jetpack infinity scroll
if (type == 'click') {
if (response.lastbatch) {
if (self.click_handle) {
$('#infinite-handle').remove();
// Update body classes
self.body.addClass('infinity-end').removeClass('infinity-success');
} else {
self.body.trigger('infinite-scroll-posts-end');
}
} else {
if (self.click_handle) {
self.element.append(self.handle);
} else {
self.body.trigger('infinite-scroll-posts-more');
}
}
} else if (response.lastbatch) {
self.disabled = true;
self.body.addClass('infinity-end').removeClass('infinity-success');
}

Windows Store Javascript background audio tassk close() method?

I have created a simple Windows 8.1 store app for just playing internet streaming radio. It looks and works good, but I can't upload my app to Windows Store! After validation a get the message like:
WinJS background task
Error Found:
The WinJS background tasks test encountered the
following errors:
App Radio Skovoroda did not call close() in the
background task JavaScript code found in file default.html.
Impact if not fixed: Apps with background tasks that do not call close() can result in draining the battery.
How to fix: Update the background
task to call close().
The point is I do not need to call close(), because it is a radio player, so, it must play in background for a long time! Any ideas? How to do my app pass the validator?
My script code:
(function () {
"use strict";
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application was suspended and then terminated.
// To create a smooth user experience, restore application state here so that it looks like the app never stopped running.
}
args.setPromise(WinJS.UI.processAll());
var buttonMediaControl = document.getElementById("mediaControlButton");
buttonMediaControl.addEventListener("click", playAndStop, false);
//add variables for social buttons
//Facebook
var fbButton = document.getElementById("fbButton");
fbButton.addEventListener("click", goToFbPage, false);
//VKotakte
var vkButton = document.getElementById("vkButton");
vkButton.addEventListener("click", goToVkPage, false);
//Twitter
var twButton = document.getElementById("twButton");
twButton.addEventListener("click", goToTwPage, false);
//Instagram
var igButton = document.getElementById("igButton");
igButton.addEventListener("click", goToIgPage, false);
//YouTube
var ytButton = document.getElementById("ytButton");
ytButton.addEventListener("click", goToYtPage, false);
//TuneIn
var tiButton = document.getElementById("tiButton");
tiButton.addEventListener("click", goToTiPage, false)
// Assign the button object to MediaControls
var systemMediaControls = Windows.Media.SystemMediaTransportControls.getForCurrentView();
systemMediaControls.addEventListener("buttonpressed", systemMediaControlsButtonPressed, false);
systemMediaControls.isPlayEnabled = true;
systemMediaControls.isPauseEnabled = true;
systemMediaControls.isStopEnabled = true;
systemMediaControls.playbackStatus = Windows.Media.MediaPlaybackStatus.closed;
}
};
app.oncheckpoint = function (args) {
};
// Plays the media.
function playMedia() {
var media = document.getElementById("skovorodaStreamingAudio");
media.play();
var statusIcon = document.getElementById("playStopImage");
statusIcon.src = "images/skovoroda_stop_button.png";
var systemMediaControls = Windows.Media.SystemMediaTransportControls.getForCurrentView();
systemMediaControls.playbackStatus = Windows.Media.MediaPlaybackStatus.playing;
}
// Pauses the media.
function pauseMedia() {
var media = document.getElementById("skovorodaStreamingAudio");
media.pause();
var statusIcon = document.getElementById("playStopImage");
statusIcon.src = "images/skovoroda_play_button.png";
var systemMediaControls = Windows.Media.SystemMediaTransportControls.getForCurrentView();
systemMediaControls.playbackStatus = Windows.Media.MediaPlaybackStatus.paused;
}
// Stops the media.
function stopMedia() {
var media = document.getElementById("skovorodaStreamingAudio");
media.pause();
media.currentTime = 0;
}
function playAndStop() {
var myAudio = document.getElementById("skovorodaStreamingAudio");
var statusIcon = document.getElementById("playStopImage");
if (myAudio.paused) {
var systemMediaControls = Windows.Media.SystemMediaTransportControls.getForCurrentView();
systemMediaControls.playbackStatus = Windows.Media.MediaPlaybackStatus.playing;
myAudio.play();
statusIcon.src = "images/skovoroda_stop_button.png";
} else {
var systemMediaControls = Windows.Media.SystemMediaTransportControls.getForCurrentView();
systemMediaControls.playbackStatus = Windows.Media.MediaPlaybackStatus.paused;
myAudio.pause();
statusIcon.src = "images/skovoroda_play_button.png";
}
}
// The media Play event handler.
function mediaPlaying() {
// Update the SystemMediaTransportControl state.
systemMediaControls.playbackStatus = Windows.Media.MediaPlaybackStatus.playing;
}
// The media Pause event handler.
function mediaPaused() {
// Update the SystemMediaTransportControl state.
systemMediaControls.playbackStatus = Windows.Media.MediaPlaybackStatus.paused;
}
// The media Ended event handler.
function mediaEnded() {
// Update the SystemMediaTransportControl state.
systemMediaControls.playbackStatus = Windows.Media.MediaPlaybackStatus.stopped;
}
function goToFbPage() {
window.open("https://www.facebook.com/radioskovoroda?__mref=message_bubble");
}
function goToVkPage() {
window.open("https://vk.com/radioskovoroda");
}
function goToTwPage() {
window.open("https://twitter.com/RadioSkovoroda");
}
function goToIgPage() {
window.open("https://instagram.com/radioskovoroda");
}
function goToYtPage() {
window.open("https://www.youtube.com/channel/UCSgkIdg5MztN_2z9q_8u3Nw")
}
function goToTiPage() {
window.open("http://tunein.com/radio/radio-skovoroda-s248591/")
}
// Event handler for SystemMediaTransportControls' buttonpressed event
function systemMediaControlsButtonPressed() {
if (Windows.Media.MediaControl.isPlaying === true) {
pauseMedia();
} else {
playMedia();
}
}
app.start();
})();

"Converting" in jQuery an audio player with multiple tracks

I have a tracklist and I'd like to serve a preview of 3 songs with just a play and pause button.
Here's the messy snippet I have right now in JS:
var playing = false;
playpause01.addEventListener('click', function () {
if (!playing) {
document.getElementById('player01').play();
this.src = 'files/img/pause.png';
} else {
document.getElementById('player01').pause();
this.src = 'files/img/play.png';
}
playing = !playing;
});
playpause04.addEventListener('click', function () {
if (!playing) {
document.getElementById('player04').play();
this.src = 'files/img/pause.png';
} else {
document.getElementById('player04').pause();
this.src = 'files/img/play.png';
}
playing = !playing;
});
playpause13.addEventListener('click', function () {
if (!playing) {
document.getElementById('player13').play();
this.src = 'files/img/pause.png';
} else {
document.getElementById('player13').pause();
this.src = 'files/img/play.png';
}
playing = !playing;
});
And for each track I have in HTML:
<audio id="player01" src="files/blabla.ogg"></audio>
<img style="position:absolute;left:-80px" id="playpause01" src="files/img/play.png" />
Now, this snippet has 2 issues:
1) I need to separetely target 3 different elements (for each song I want to preview)
2) If I play a new song while playing one the 2 songs overlap.
I think rewriting the snippet in jQuery would be much easier. How could I solve the 2 issues?
Here's the JsFiddle to start from:
http://jsfiddle.net/multiformeingegno/jdk0b5L4/
You can use a common listener like this:
$('ol').on('click', 'li img', playAudio);
var currentlyPlaying;
function playAudio(e){
var audElement = $(e.target).siblings('audio')[0];
window.aa = audElement;
if(audElement && audElement.paused){
if(currentlyPlaying)
currentlyPlaying.pause();
currentlyPlaying = audElement;
addListeners(currentlyPlaying);
currentlyPlaying.play();
}else if(audElement){
audElement.pause();
}
}
function addListeners(aud){
aud.removeEventListener('ended', onPause); // remove done to remove previous listener
aud.removeEventListener('pause', onPause);
aud.removeEventListener('playing', onPlay);
aud.addEventListener('ended', onPause);
aud.addEventListener('pause', onPause);
aud.addEventListener('playing', onPlay);
}
function onPlay(e){
$(e.target).siblings('img')[0].src = 'http://luca-longobardi.com/files/img/pause.png';
}
function onPause(e){
e.target.currentTime = 0; // reset to beginning
$(e.target).siblings('img')[0].src = 'http://luca-longobardi.com/files/img/play.png';
}
fiddle demo

Categories