I'm trying to set the current time for the last video in the playlist, but it always fails.
This is the code I'm working on with my try.
It doesn't set the time at all and I don't know how to solve.
var iframe = document.querySelector('iframe.main-player');
var player = new Vimeo.Player(iframe);
var video_ids = [123456789, 987654321, 543216789];
var index = 0;
var playNext = function(data) {
if (index <= video_ids.length)
player.loadVideo(video_ids[index++])
}
let last = video_ids.length - 1;
player.loadVideo(video_ids[index++]);
player.on('loaded', function() {
if (last == index++) {
player.setCurrentTime(200);
}
player.play();
});
player.on('ended', playNext);
Related
I would like my audio2 file to play when audio1.currentTime is 3 seconds, but I'm not able to make it work. I'm a newbie in javascript, what am I missing?. This is my current javascript code:
function initAudioPlayer(){
var audio1, audio2, ext, agent;
ext = ".mp3";
agent = navigator.userAgent.toLocaleLowerCase();
if(agent.indexOf('firefox') != -1 || agent.indexOf('opera') != -1) { ext = ".ogg";}
//Audio Objects: audio1 and audio2
audio1 = new Audio();
audio1.src = "folder/Audio1"+ext;
audio1.loop = false;
audio1.play();
audio2 = new Audio();
audio2.src = "folder/Audio2"+ext;
audio2.loop = false;
audio2.play();
//Function that reproduces the second audio file at second 3 of the first audio file
function audio2(){
if(audio1.currentTime == 3) {audio2.play();}
};
}
window.addEventListener("load", initAudioPlayer);
You Must use Audio Api and fetch buffers of your files.
Then you must plus each byte and copy to another new buffer.
this code can help you:
let idnex=0;
samples.forEach(buufer => {
if (index === 0) {
tempBuf = buufer;
} else {
tempBuf = this.appendBuffer(tempBuf, buufer);
}
index++;
});
and by thi method you can append two buffer:
private appendBuffer(buffer1, buffer2) {
const numberOfChannels = Math.min(buffer1.numberOfChannels, buffer2.numberOfChannels);
const tmp = this.audioContextService.createBuffer(Math.max(buffer1.numberOfChannels, buffer2.numberOfChannels),
Math.max(buffer1.length, buffer2.length), buffer1.sampleRate);
for (let i = 0; i < numberOfChannels; i++) {
const channel = tmp.getChannelData(i);
let finallArray = [];
let d = [];
const chanelTemp = buffer1.getChannelData(i);
if (buffer2.numberOfChannels <= i) {
finallArray = chanelTemp;
} else {
const c = buffer2.getChannelData(i);
if (chanelTemp.length > c.length) {
finallArray = chanelTemp;
d = c;
} else {
finallArray = c;
d = chanelTemp;
}
for (let j = 0; j < d.length; j++) {
finallArray[j] += d[j] / 2;
}
}
channel.set(finallArray, i);
}
you can see my demo here
Also You Can See this Answer
If you truly want this to be accurate in time, you can't use Audio() - that's the HTML5 <audio> element, which is not sample-accurate. Javascript is also not accurate enough in event delivery to use a callback to do this (to be fair, neither are most general-purpose native OS APIs). You need to schedule the playback in advance, which is where Web Audio (https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API) comes in. You need to load both samples, decode them into AudioBuffers, and then schedule playing back each of them with an AudioBufferSourceNode.
So i have a bunch of loaded audio samples that I am calling the schedule function with in the code below:
let audio;
function playChannel() {
let audioStart = context.currentTime;
let next = 0;
for(let i = 0; i < 8; i++) {
scheduler(audioStart, next);
next++;
}
}
Here is the audio scheduler function:
function scheduler(audioStart, index) {
audio = context.createBufferSource();
audio.buffer = audioSamples[index]; //array with all the loaded audio
audio.connect(context.destination);
audio.start(audioStart + (audio.buffer.duration * index));
}
And it's working fine and plays the scheduled sounds as it should.
How am I supposed to stop/cancel all the scheduled sounds from playing?
Because right now when I try to call the stop() method it will only stop the last scheduled sound from playing.
You'll need to keep track of the BufferSource nodes you're creating inside scheduler, referenced by index, and then run through all of them. E.g.:
var sources = [];
function scheduler(audioStart, index) {
audio = context.createBufferSource();
sources[index] = audio;
audio.buffer = audioSamples[index]; //array with all the loaded audio
audio.connect(context.destination);
audio.start(audioStart + (audio.buffer.duration * index));
}
function stopAll() {
for(let i = 0; i < 8; i++)
if (sources[i])
sources[i].stop(0);
}
Js beginner here.
I have a function like this:
generateSteps: function() {
var stepsLength = this.data.steps.length;
var dataStepsInit = this.data.steps;
for (var i = 0; i < stepsLength; i++) {
var stepsItem = dataStepsInit[i].ITEM;
var arrayItem = this.animationNodes[stepsItem - 1];
var transition = this.animationParameters[i].transition;
var options = this.animationParameters[i].options;
var speed = this.animationParameters[i].speed;
var delay = this.animationParameters[i].delay;
arrayItem.delay(delay).show(transition, options, speed);
if (dataStepsInit[i].AUDIOID) {
var audioClass = dataStepsInit[i].AUDIOID;
var audioPlayer = this.template.find("audio." + audioClass);
setTimeout(playAudioOnDelay,delay);
};
var playAudioOnDelay = function() {
audioPlayer[0].pause();
audioPlayer[0].currentTime = 0;
audioPlayer[0].play();
};
}
}
What it does is generate data from JSON and display animated elements one by one on delay. Animation part work fine. I can assign required animations and delay to DOM elements and show them in right order.
But what I want to do in the same time is also to play an audio on delay (so I use setTimeout). Everything is almost fine, I play audio in right time (correct delay value) but I always play the same audio (which is last element) because audioPlayer always is the same DOM node.
I think this have something to do with this or I mixed a scope?
Try this:
generateSteps: function() {
var stepsLength = this.data.steps.length;
var dataStepsInit = this.data.steps;
for (var i = 0; i < stepsLength; i++) {
var stepsItem = dataStepsInit[i].ITEM;
var arrayItem = this.animationNodes[stepsItem - 1];
var transition = this.animationParameters[i].transition;
var options = this.animationParameters[i].options;
var speed = this.animationParameters[i].speed;
var delay = this.animationParameters[i].delay;
arrayItem.delay(delay).show(transition, options, speed);
if (dataStepsInit[i].AUDIOID) {
var audioClass = dataStepsInit[i].AUDIOID;
var audioPlayer = this.template.find("audio." + audioClass);
setTimeout(playAudioOnDelay(audioPlayer),delay);
};
}
function playAudioOnDelay(audioPlayer){
return function(){
audioPlayer[0].pause();
audioPlayer[0].currentTime = 0;
audioPlayer[0].play();
}
}
}
Essentially, your problem looks like this: http://jsfiddle.net/po0rLnwo/
The solution is : http://jsfiddle.net/gpfuo1s8/
Check the console in your browser.
I'm new to programming. I just want to know, how do I highlight the current chapter while playing the video on the chapter menu of the youtube chapter marker player.
Live link : http://gdata-samples.googlecode.com/svn/trunk/ytplayer/ChapterMarkerPlayer/index.html
Full CSS : http://gdata-samples.googlecode.com/svn/trunk/ytplayer/ChapterMarkerPlayer/chapter_marker_player.css
Full javascript : http://gdata-samples.googlecode.com/svn/trunk/ytplayer/ChapterMarkerPlayer/chapter_marker_player.js
Can anyone please provide me some codes or samples similar to this. So, I can get some idea how to do this.. Thank you very much :)
The youtube api has this script
function getCurrentTime() {
ytplayer.getCurrentTime();
}
Where "ytplayer" is your targeted player.
I would say then you can use
setInterval(getCurrentTime(), 3000);
and check if it matches.
You would need to have var's set up with values to test against.
= to ? but < ??
After that the script can change the css of the div accordingly. onClick would need to have the same result.
New Codes:
function clearList() {
var list = document.getElementById("chapter-list");
var items = list.getElementsByTagName("li");
for (var i = 0; i < items.length; i++) {
items[i].removeAttribute("class");
}
}
function highlightChapter(player) {
setInterval(function() {
var status = player.getPlayerState();
if (status>0) {
var currentTime = player.getCurrentTime() ;
list = document.getElementById('chapter-list');
for (var i = 0; i < times.length; i++) {
var time = times[i];
var item = list.children[i];
if (currentTime>=time) {
clearList();
item.setAttribute('class', 'current');
}
}
}
}, 1000);
}
Edited Code:
function addChapterMarkers(containerElement, player) {
var ol = document.createElement('ol');
ol.setAttribute('class', 'chapter-list');
ol.setAttribute('id', 'chapter-list'); ////////////// HERE
ol.setAttribute('style', 'width: ' + width + 'px');
containerElement.appendChild(ol);
for (var i = 0; i < times.length; i++) {
var time = times[i];
var chapterTitle = params.chapters[time];
var li = document.createElement('li');
li.setAttribute('data-time', time);
li.textContent = formatTimestamp(time) + ': ' + chapterTitle;
li.onclick = function() {
// 'this' will refer to the element that was clicked.
player.seekTo(this.getAttribute('data-time'));
//my code
clearList(); //// ADDITIONAL CODE
this.setAttribute('class', 'current'); //// ADDITIONAL CODE
// end my code
};
ol.appendChild(li);
}
}
function insertPlayerAndAddChapterMarkers(params) {
var containerElement = document.getElementById(params.container);
if (!containerElement) {
throw 'The "container" parameter must be set to the id of a existing HTML element.';
}
var player = initializePlayer(containerElement, params);
addChapterMarkers(containerElement, player);
highlightChapter(player); ////// INSERT
}
I have several tracks to a song that I want to play together and be able to mute some and play others. So I need to be able to start them all at the same time. Right now, they all start slightly out of sync:
// Start playing
for ( i = 0; i < 5; i++ ) {
tracks[i].audio.play();
}
Even this is apparently not fast enough to start them all at the same time.
Is there any way in javascript to guarantee that HTML5 audio tags will start playing simultaneously?
Not sure if you're already doing this, but Here's some sample code for preloading audio.
var audios = [];
var loading = 0;
AddNote("2C");
AddNote("2E");
AddNote("2G");
AddNote("3C");
function AddNote(name) {
loading++;
var audio = document.createElement("audio");
audio.loop = true;
audio.addEventListener("canplaythrough", function () {
loading--;
if (loading == 0) // All files are preloaded
StartPlayingAll();
}, false);
audio.src = "piano/" + name + ".mp3";
audios.push(audio);
}
function StartPlayingAll() {
for (var i = 0; i < audios.length; i++)
audios[i].play();
}
}
The other thing you can try is setting audio.currentTime on each of the tracks to manually sync up the audio.
You could use setTimeout to sync them after a brief delay in the beginning (you may want to wait for all the audio objects to load though).
JSFiddle: http://jsfiddle.net/bmAYb/35/
var au1 = document.getElementById('au1');
var au2 = document.getElementById('au2');
au1.volume = 1;
au2.volume = 0; //mute
au1.play();
au2.play();
var notfirstRun = false;
//sync for the first time
setTimeout(function() {
au2.currentTime = au1.currentTime;
au2.volume = 1;
}, 250);
My initial thought was to sync every x miliseconds using setInterval, but the audio pops when you do that if volume is set to 1 (audible).
My fiddle isn't totally in sync, but it's pretty close. You can get it 100% in sync but you either need to mute the audio on the other tracks or deal with popping.
The code (and music in the fiddle) are from Hungry Media.
I had the same issue and found a solution using the Audio API.
The problem is that the audio output has a delay of a few milliseconds, so it is impossible to start multiple audios at the same time. However, you can get around this by merging the audio sources into one using a ChannelMergerNode. By putting GainNodes in between, you can control the volume of each audio source separately.
I wrote a simple javascript class for this. This is how you can use it:
var audioMerger = new AudioMerger(["file1.ogg", "file2.mp3", "file3.mp3",
"file4.ogg", "file5.mp3"]);
audioMerger.onBuffered(() => audioMerger.play());
// Make sure it's always in sync (delay should be less than 50 ms)
setInterval(() => {
if (audioMerger.getDelay() >= 0.05) {
audioMerger.setTime(audioMerger.getTime());
}
}, 200);
// Set volume of 3rd audio to 50%
audioMerger.setVolume(0.5, 2);
// When you want to turn it off:
audioMerger.pause();
This code reduced the delay between the audios to less than 10 milliseconds in Firefox on my PC. This delay is so small you won't notice it. Unfortunately, it doesn't work in older browsers like Internet Explorer.
And here's the code for the class:
class AudioMerger {
constructor(files) {
this.files = files;
this.audios = files.map(file => new Audio(file));
var AudioContext = window.AudioContext || window.webkitAudioContext;
var ctx = new AudioContext();
this.merger = ctx.createChannelMerger(this.audios.length);
this.merger.connect(ctx.destination);
this.gains = this.audios.map(audio => {
var gain = ctx.createGain();
var source = ctx.createMediaElementSource(audio);
source.connect(gain);
gain.connect(this.merger);
return gain;
});
this.buffered = false;
var load = files.length;
this.audios.forEach(audio => {
audio.addEventListener("canplaythrough", () => {
load--;
if (load === 0) {
this.buffered = true;
if (this.bufferCallback != null) this.bufferCallback();
}
});
});
}
onBuffered(callback) {
if (this.buffered) callback();
else this.bufferCallback = callback;
}
play() {
this.audios.forEach(audio => audio.play());
}
pause() {
this.audios.forEach(audio => audio.pause());
}
getTime() {
return this.audios[0].currentTime;
}
setTime(time) {
this.audios.forEach(audio => audio.currentTime = time);
}
getDelay() {
var times = [];
for (var i = 0; i < this.audios.length; i++) {
times.push(this.audios[i].currentTime);
}
var minTime = Math.min.apply(Math, times);
var maxTime = Math.max.apply(Math, times);
return maxTime - minTime;
}
setVolume(volume, audioID) {
this.gains[audioID].gain.value = volume;
}
}