How do I play a sound file after another sound ends? If I do it like
first.play();
second.play();
Both the sounds play at the same time. I want to play first.play() and when it ends, starts second.play().
first.addEventListener('ended', function(){
second.play();
});
first.play();
I would recommend kind of something:
// if using jQuery:
var audios = $('audio');
audios.each(function(idx){
$(this).bind('ended', function(){
var next = audios.get(idx+1);
if(next){
next.get(0).play();
}
});
});
You can also use a promise with a timeout:
const playPromise = first.play()
playPromise.then(() => {
setTimeout(() => {second.play()}, first.duration * 1000)
})
I used the AudioScheduledSourceNode.onended.
I used four sounds, and put this code in a function:
sound1.play();
sound1.onended = function () {
sound2.play();
};
sound2.onended = function () {
sound3.play();
};
sound3.onended = function () {
sound4.play();
}
Here is the app live: insultinator-toy.netlify.app
Click the question mark button.
And the link to the ugly source code. jsahlsa
Related
I am trying to create a SoundCloud music player. It can play any track from SoundCloud, but this plugin is only working if there is only one instance of it in the page. So it wont work if two of the same plugin are in the page.
Here is an example of having two players in the page: JSFiddle
var trackURL = $(".player").text();
$(".player").empty();
$(".player").append("<div class='playBTN'>Play</div>");
$(".player").append("<div class='title'></div>");
var trackId;
SC.get('/resolve', { url: trackURL }, function (track) {
var trackId = track.id;
//var trackTitle = track.title;
$(".title").text(track.title);
$(".playBTN").on('click tap', function () {
//trackId = $(".DSPlayer").attr('id');
stream(trackId);
});
// first do async action
SC.stream("/tracks/" + trackId, {
useHTML5Audio: true,
preferFlash: false
}, function (goz) {
soundToPlay = goz;
sound = soundToPlay;
scTrack = sound;
//updater = setInterval( updatePosition, 100);
});
});
var is_playing = false,
sound;
function stream(trackId) {
scTrack = sound;
if (sound) {
if (is_playing) {
sound.pause();
is_playing = false;
$(".playBTN").text("Play");
} else {
sound.play();
is_playing = true;
$(".playBTN").text("Pause");
}
} else {
is_playing = true;
}
}
If you remove any of these div elements that hold the .player class, the other element will work. So it only doesn't work because there are two instances of the same plugin.
How can I fix it? to have multiple instances of the player in one page?
I have identified the problem. It has to do with the fact that you are trying to load multiple tracks at the same time, but have not separated the code to do so.
As #Greener mentioned you need to iterate over the .player instances separately and execute a SC.get() for each one of them.
Here is what I see happening that is causing the problem:
var trackURL = $(".player").text();
^The code above returns a string that contains both of the URLs you want to use back-to-back without spaces. This creates a problem down the road because of this code:
SC.get('/resolve', { url: trackURL }, function (track) {...
That is a function that is trying to load the relevant song from SoundCloud. You are passing it a variable "trackURL" for it to try and load a specific URL. The function gets a string that looks like "URLURL" what it needs is just "URL".
What you can do is iterate over all the different ".player" elements that exist and then call the sounds that way. I modified your script a little to make it work using a for loop. I had to move the "empty()" functions into the for loop to make it work correctly. You have to use .eq(index) when referring to JQuery array of elements.
Like this:
var trackURL
var trackId;
for(index = 0; index < $(".player").length; index++){
trackURL = $(".player").eq(index).text();
//alert(trackURL);
$(".player").eq(index).empty();
$(".player").eq(index).append("<div class='playBTN'>Play</div>");
$(".player").eq(index).append("<div class='title'></div>");
SC.get('/resolve', { url: trackURL }, function (track) {
var trackId = track.id;
alert(track.id);
//var trackTitle = track.title;
$(".title").eq(index).text(track.title);
$(".playBTN").eq(index).on('click tap', function () {
//trackId = $(".DSPlayer").attr('id');
stream(trackId);
});
// first do async action
SC.stream("/tracks/" + trackId, {
useHTML5Audio: true,
preferFlash: false
}, function (goz) {
soundToPlay = goz;
sound = soundToPlay;
scTrack = sound;
//updater = setInterval( updatePosition, 100);
});
});
}
This is not a completely finished code here, but it will initiate two separate songs "ready" for streaming. I checked using the commented out alert what IDs SoundCloud was giving us (which shows that its loaded now). You are doing some interesting stuff with your streaming function and with the play and pause. This should give you a good idea on what was happening and you can implement your custom code that way.
I'm trying to count the time that player is holding the mouse button down. I tried this but it didn't works:
var Game = cc.Layer.extend({
count: false,
countTimer: null,
init: function () {
var selfPointer = this;
this.canvas.addEventListener('mousedown', function(evt) {
selfPointer.count = true;
selfPointer.countTimer = window.setTimeout(selfPointer.Count(), 1);
});
this.canvas.addEventListener('mouseup', function(evt) {
selfPointer.count= false;
window.clearTimeout(selfPointer.countTimer);
});
},
Count: function() {
if (this.count)
{
window.setTimeout(this.Count(), 1);
}
}
This is a part of my code(for brevity) that I want to do an action any 1 milisecond if player is holding the button.
This isn't working besides, I presume that is a better way to do this than mine way. Any ideas?
Why do you use timeouts for this simple task? You can just get time of mousedown, time of mouseup and calculate difference of them. Anyway, timer resolution in browsers is less than 1ms. Read this article of Nickolas Zakas to get more info about time resolution.
Code is:
var Game = cc.Layer.extend({
init: function () {
var holdStart = null,
holdTime = null;
this.canvas.addEventListener('mousedown', function(evt) {
holdStart = Date.now()
});
this.canvas.addEventListener('mouseup', function(evt) {
holdTime = Date.now() - holdStart;
// now in holdTime you have time in milliseconds
});
}
Well if you are targeting newer browsers that are HTML5 compatible you can use web workers for this kind of task. Simply post a message to the web worker on mouse press to start the timer. The web worker can post a message back every 1 ms ish to trigger your in game action and then on mouse release, post another message to the web worker telling it to stop.
Here is just a quick example of how that would work. You would need to run from a local server to have web workers working.
Game.js
function start() {
var worker = new Worker("ActionTrigger.js");
worker.addEventListener('message', function(objEvent) {
console.log("Holding");
});
worker.postMessage("start");
window.onmousedown = function() {
console.log("Mouse press");
worker.postMessage("startTrigger");
}
window.onmouseup = function() {
console.log("Mouse release");
worker.postMessage("endTrigger");
}
}
ActionTrigger.js
var trigger = false;
var interval = 1;
self.addEventListener('message', function(objEvent) {
if(objEvent.data == 'startTrigger')
trigger = true;
else if(objEvent.data == 'endTrigger')
trigger = false;
else if(objEvent.data == 'start')
timerCountdown();
});
function timerCountdown() {
if(trigger)
postMessage("");
setTimeout(timerCountdown,interval);
}
You could use something like this:
http://jsfiddle.net/yE8sh/
//Register interval handle
var timer;
$(document).mousedown(function(){
//Starts interval. Run once every 1 millisecond
timer=self.setInterval(add,1);
});
$(document).mouseup(function(){
//Clears interval on mouseup
timer=window.clearInterval(timer);
});
function add(){
//The function to run
$("body").append("a");
}
I am making a simple multiple user playlist application. I have one client watching the stream of videos, and in another I am trying to add a video to that playlist. The video adds to the playlist correctly, but when the update happens the page re renders and the video restarts on the client that is just watching. I am trying to get it so that when other users add videos to the playlist, it continues to play for all who are watching it.
On the server I have:
Meteor.publish('videosQue', function (room_id) {
return Videos.find({room_id: room_id});
});
And on the client I set it up like the todo example:
var videosHandle = null;
Deps.autorun(function(){
var room_id = Session.get('room_id');
if (room_id)
videosHandle = Meteor.subscribe('videosQue', room_id);
else
videosHandle = null;
});
And then here is some code that applies to when a person is in a room:
Template.EnteredRoom.loading = function () {
return videosHandle && !videosHandle.ready();
};
Template.EnteredRoom.room = function () {
return Rooms.findOne(Session.get('room_id'));
};
Template.EnteredRoom.video_objs = function () {
Session.set('videos', Videos.findOne({room_id: Session.get('room_id')}))
return Session.get('videos');
};
Template.EnteredRoom.rendered = function () {
if (Session.get('videos') && Session.get('videos').videoIds.length) {
var currVid = 0, playlist = Session.get('videos').videoIds;
renderVid(playlist, currVid);
};
};
var renderVid = function(playlist, currVid) {
var video = Popcorn.youtube('#youtube-video', 'http://www.youtube.com/embed/' + playlist[currVid] + '&autoplay=1');
video.on("ended", function() {
if (++currVid < playlist.length)
renderVid(playlist, currVid);
else {
$('#youtube-video').hide();
$('#video-container').append('<div style="font-size:30px;color:white;">No Videos :( Try adding one!</div>');
}
});
}
Is there anyway to get this done?
Thanks for the Help!
Andrew
EDIT:
After doing some reading I think that I should somehow use isolate to achieve this, any advice?
I think you can try putting the part that you don't need reactive in the {{#constant}} block.
{{#constant}}
{{#each ...}}
....
{{/each}}
{{/constant}}
I prefer to do it disable the reactive from collection with { reactive: false } option, in your model function:
return collection.find({}, {reactive:false}) }
I've been trying to play a track from Soundcloud at a specific position.
I have used the code from the following question as a reference
Soundcloud API: how to play only a part of a track?
below is the code that I have used
function playTrack(id) {
SC.whenStreamingReady(function() {
var sound = SC.stream(id);
sound.setPosition(240000); // position, measured in milliseconds
console.log(sound.position)
sound.play()
});
}
The console.log returns 0 and the track plays from the beginning.
alternative code I have tried and had the same result with is below
SC.stream("/tracks/" + id, function(sound){
console.log("playing")
console.log(sound)
sound.setPosition(120000)
console.log(sound.position)
sound.play()
})
Since soundcloud no longer uses soundmanager. the above methods will no longer work.
What must be done is to use a function called "seek()" instead of "setPosition()"
sound.seek(1500);
Here's a better example:
SC.stream(
"/tracks/[trackID]",
function(sound){
sound.seek(1500)
});
And if you wanted to access the seek function outside of the callback I would do this:
var soundTrack;
SC.stream(
"/tracks/[trackID]",
function(sound){
soundTrack = sound;
});
var buttonClickEvent = function(){
soundTrack.seek(1500);
}
According to SoundCloud's docs they are using SoundManager2 to handle playback, so you should be able to use any of its methods or settings. Try this:
function playTrack(id) {
SC.whenStreamingReady(function() {
var sound = SC.stream(id, {
from: 120000, // position to start playback within a sound (msec)
autoLoad: true,
autoPlay: true,
onplay: function(){ console.log(this.position) }
});
});
}
If that doesn't work you can try this instead:
function playTrack(id) {
SC.whenStreamingReady(function() {
var sound = SC.stream(id, { autoPlay: false }, function(sound){
sound.setPosition(240000); // position, measured in milliseconds
console.log(sound.position);
sound.play();
});
sound.load();
});
}
This should work-
var play_sound = function(id) {
SC.whenStreamingReady(function() {
var sound = SC.stream("/tracks/"+id,{autoPlay: false}, function(sound) {
sound.play({
whileplaying: function() {
console.log( this.position );
}
});
});
});
}
Context: On my product website I have a link for a Java webstart application (in several locations).
My goal: prevent users from double-clicking, i. e. only "fire" on first click, wait 3 secs before enabling the link again. On clicking, change the link image to something that signifies that the application is launching.
My solution works, except the image doesn't update reliably after clicking. The commented out debug output gives me the right content and the mouseover callbacks work correctly, too.
See it running here: http://www.auctober.de/beta/ (click the Button "jetzt starten").
BTW: if anybody has a better way of calling a function with a delay than that dummy-animate, let me know.
JavaScript:
<script type="text/javascript">
<!--
allowClick = true;
linkElements = "a[href='http://www.auctober.de/beta/?startjnlp=true&rand=1249026819']";
$(document).ready(function() {
$('#jnlpLink').mouseover(function() {
if ( allowClick ) {
setImage('images/jetzt_starten2.gif');
}
});
$('#jnlpLink').mouseout(function() {
if ( allowClick ) {
setImage('images/jetzt_starten.gif');
}
});
$(linkElements).click(function(evt) {
if ( ! allowClick ) {
evt.preventDefault();
}
else {
setAllowClick(false);
var altContent = $('#jnlpLink').attr('altContent');
var oldContent = $('#launchImg').attr('src');
setImage(altContent);
$(this).animate({opacity: 1.0}, 3000, "", function() {
setAllowClick(true);
setImage(oldContent);
});
}
});
});
function setAllowClick(flag) {
allowClick = flag;
}
function setImage(imgSrc) {
//$('#debug').html("img:"+imgSrc);
$('#launchImg').attr('src', imgSrc);
}
//-->
</script>
A delay can be achieved with the setTimeout function
setTimeout(function() { alert('something')}, 3000);//3 secs
And for your src problem, try:
$('#launchImg')[0].src = imgSrc;
Check out the BlockUI plug-in. Sounds like it could be what you're looking for.
You'll find a nice demo here.
...or just use:
$(this).animate({opacity: '1'}, 1000);
wherever you want in your code, where $(this) is something that is already at opacity=1...which means everything seemingly pauses for one second. I use this all the time.
Add this variable at the top of your script:
var timer;
Implement this function:
function setFlagAndImage(flag) {
setAllowClick(flag);
setImage();
}
And then replace the dummy animation with:
timer = window.setTimeout(function() { setFlagAndImage(true); }, 3000);
If something else then happens and you want to stop the timer, you can just call:
window.clearTimeout(timer);