Play an audio with corresponding sequence of images being animated w/ play & pause - javascript

I'm trying to create an animation of series of images with background audio using HTML5 and javascript maybe ajax or jquery. I'm basically trying to make an animation of a simple conversation between several people (portrayed by images) and speech through (audio).
I have an audio file (mp3/ogg) and a series of images. When I play the audio, the sequence of images will be displayed accordingly.
Here's the catch, If I pause or replay the audio, sequence of image must also stop or replay from the start.
So the sequence of images must be in sync with the audio playing.
Any ideas or concepts? Right now I have a working jPlayer with play/pause. Also can it be done with jPlayer?

Just make your decisions based on the currentTime of your audio. Example
var audio = document.querySelector('audio'),
img = document.querySelector('img'),
imgs = ['http://raptorsrepublic.com/wp-content/uploads/2012/08/meh_cat.jpg', 'http://2.bp.blogspot.com/_8tZf9lm-smo/R7hn7pNx-jI/AAAAAAAAALI/86DN7VedT_Q/s400/meh.jpg', 'http://2.bp.blogspot.com/-yWsoWNVX4jU/UAy5uJxD52I/AAAAAAAANSc/OTje6k_C5Q8/s1600/meh2.jpg'],
duration, interval, currentImg;
(function callee(ready) {
if (ready !== false) ready = true;
if (!ready) {
return audio.addEventListener('canplaythrough', callee);
}
if (!audio.playing) audio.play();
if (!duration) {
duration = audio.duration;
interval = duration / imgs.length;
}
if (isNaN(duration)) return setTimeout(callee, 1000);
var currentTime = audio.currentTime;
if (!currentImg) {
img.src = currentImg = imgs[0];
}
var currentTimeImage = imgs[Math.floor(currentTime / interval)];
if (currentTimeImage != currentImg) {
img.src = currentImg = currentTimeImage;
}
setTimeout(callee, 1000);
})(false);

Related

How do i make audio pause in javascript/jquery?

I tried making a visual novel for learning. I can't figure out how to stop/pause my audio file in javascript/jQuery.
I want to play and pause different music if a character appears. They appear if the counter has a certain value - the music has to do the same. The music starts playing when the data-current is at 2 but doesn't pause/stop with the method pause() at data-current == 5
How can I solve this problem?
$('#textbox').click(function () {
// ...
var musics = ['MagicalForest.mp3', 'bunnymusic.mp3', ]
var IntroAudio = new Audio(musics[0]);
var bunnyAudio = new Audio(musics[1]);
if ($('#textbox').attr('data-current') == 2) {
IntroAudio.play();
}
if ($('#textbox').attr('data-current') == 5) {
IntroAudio.pause();
bunnyAudio.play();
};
};

Web API MediaRecorder: How do I force record at 60fps?

Summary
The API I speak about
The context
The problem: Actual result + Expected result
What I already have tried
Clues to help you to help me
Minimal and Testable Example: Prerequisites and Steps to follow + Sources
The API I speak about
https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder
The context
I have a video element that I load & play several times with different src. Between two different videos, a transition occures and each video appears with a fade in. When a video is playing, I draw it in a canvas with the transition and the fade in.
Everything I draw in the canvas is recorded using the Web API MediaRecorder. Then I download the WEBM file corresponding to this recording.
The problem
Actual result
The resulting WEBM is jerky. When I drew in the canvas, the drawing was fluid. But the WEBM resulting from the recording of the canvas drawing is jerky.
Expected result
The WEBM resulting from the recording of the canvas drawing must be as fluid as the canvas drawing itself. If it's impossible to have exactly this result, then: the WEBM must be approximately as fluid as the canvas drawing itself in a way that we quite can't say it's jerky.
What I have already tried
First, I've tried to set a time slice of 1ms, of 16ms (corresponding to 60fps), of 100ms, then 1000, then 10000, etc. to the method start of the Media Recorder, but it didn't work.
Second, I've tried to call requestData every 16ms (in a simple JS timeoutlistener executed every 16ms), but it didn't work.
Clues to help you to help me
Perhaps I'm wrong but it would be possible that a material limit exist on my computer (I have a HP Spectre x360 that doesn't have graphic card, but just a little graphics chip), or a logical limit on my Chromium browser (I have Version 81.0.4044.138 on my Ubuntu 16.04 LTS).
If you can confirm this it would solve this question. If you can explain how to deal with this problem it would be very good (alternative solution to the Web API Media Recorder, or something else).
Minimal and Testable Example
Prerequisites and Steps to follow
Have at least 2 WEBM videos (which will be the input videos, remember: we want to output a new video that contains the canvas drawing, which itself contains these two input videos plus transitions and colors effects etc.)
Have a HTTP server and a file called "index.html" that you will open with Chromium v.81 e.g.. Copy/paste the following sources inside ; click on the "Start" button (you won't need to click on the "Stop" button) ; it will draw both videos on the canvas, with the transitions & colors effects, it will record the canvas drawing, and a "Download the final output video" will appear, allowing you to download the output video. You will see that it's jerky.
In the following sources, copy/paste the paths of your videos in the JS array called videos.
Sources
<html>
<head>
<title>Creating Final Video</title>
</head>
<body>
<button id="start">Start</button>
<button id="stop_recording">Stop recording</button>
<video id="video" width="320" height="240" controls>
<source type="video/mp4">
</video>
<canvas id="canvas" width=3200 height=1608></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
var videos = []; // Populated by Selenium
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var video = document.querySelector("video");
startRecording();
$('#start').click(function() {
showSomeMedia(0, 0);
});
function showSomeMedia(videos_counter) {
resetVideo();
if(videos_counter == videos.length) {
$('#stop_recording').click();
return;
} else {
setVideoSrc(videos_counter);
setVideoListener();
videos_counter++;
}
video.addEventListener('ended', () => {
showSomeMedia(videos_counter);
}, false);
}
function resetVideo() {
var clone = video.cloneNode(true);
video.remove();
video = clone;
}
function setVideoSrc(videos_counter) {
video.setAttribute("src", videos[videos_counter]);
video.load();
video.play();
}
function setVideoListener() {
var alpha = 0.1;
video.addEventListener('playing', () => {
function step() {
if(alpha < 1) {
ctx.globalAlpha = alpha;
}
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
requestAnimationFrame(step)
if(alpha < 1) {
alpha += 0.00001;
}
}
requestAnimationFrame(step);
}, false)
}
function startRecording() {
const chunks = [];
const stream = canvas.captureStream();
const rec = new MediaRecorder(stream);
rec.ondataavailable = e => chunks.push(e.data);
$('#stop_recording').click(function() {
rec.stop();
});
rec.onstop = e => exportVid(new Blob(chunks, {type: 'video/webm'}));
window.setTimeout(function() {
rec.requestData();
}, 1);
rec.start();
}
function exportVid(blob) {
const vid = document.createElement('video');
vid.src = URL.createObjectURL(blob);
vid.controls = true;
document.body.appendChild(vid);
const a = document.createElement('a');
a.download = 'my_final_output_video.webm';
a.href = vid.src;
a.textContent = 'Download the final output video';
document.body.appendChild(a);
}
</script>
</body>
</html>
The problem is solved by using my gaming laptop (RoG), wich has a good graphic card, able to record at higher frequency than my Spectre x360 development laptop.

Play Html5 video and pause at specific points in time

I have an array of points in time (seconds) like this :
var points = [1,5,7,9,23,37];
I want the video to play from 1 to 5 and then pause. Then some event happens (like button click) and it plays from 5 to 7 and then pauses and so on. How can I do this using js/jquery ?
Just queue up the times (currentStopTime) and check the currentTime of the video. If currentTime >= currentStopTime then pause video, set currentStopTime to next time in the array.
var points = [1,5,7,9,23,37],
index = 1,
currentStopTime = points[index];
// start video using: video.currentTime = points[0], then video.play()
// run this from a timeupdate event or per frame using requestAnimationFrame
function checkTime() {
if (video.currentTime >= currentStopTime) {
video.pause();
if (points.length > ++index) { // increase index and get next time
currentStopTime = points[index]
}
else { // or loop/next...
// done
}
}
}
Then when paused, enable an action to happen, simply call play() to start video again. If you need an accurate restart time then force that time by adding:
...
if (video.currentTime >= currentStopTime) {
video.pause();
video.currentTime = currentStopTime;
index++;
....

How to play next/previous audio file using bezel in Gear s2?

developing Web app for gear s2, I am trying to play next/previous audio file when bezel is rotated clockwise/counterclockwise.
just like the "Music Player" on the watch.
what I tried so far is as follows, but only the second song plays when I rotate the bezel clockwise and when I rotate CCW, only the first song plays.
I don't know how to write it so that EACH time that I rotate the bezel, it goes to the next song.
var audio = new Audio();
var source = ["songs/coldplay.mp3", "songs/abba.mp3", "songs/goodbye.mp3", "songs/sleep.mp3"];
var i = 0;
var current = null;
rotaryDetentHandler = function(e) {
direction = e.detail.direction;
if (direction === "CW") {
if(i <source.length)
i++;
else i=source.length;
}
if (direction === "CCW") {
if(i>0)
i-- ;
else i = 0;
}
if(current !=null)
{stop();}
audio.src = source [i];
audio.load();
audio.play();
current = audio;
}
function stop()
{
current.pause();
}
Hopefully someone can find out what the problem is or if there is another way to do it.
Thank you.
for anyone having this problem, I finally found out what the problem is.
You have to add an EventListener to the page, like below:
page.addEventListener("pagebeforeshow", function() {
// do something
});

Custom progress bar for <audio> and <progress> HTML5 elements

I am mind boggled at working out how to create a custom seekbar for an audio player using the tag and simple Javascript.
Current Code:
<script>
function play() {
document.getElementById('player').play();
}
function pause() {
document.getElementById('player').pause();
}
</script>
<audio src="sample.mp3" id="player"></audio>
<button onClick="javascript:play()" >Play</button>
<button onClick="javascript:pause()" >Pause</button>
<progress id="seekbar"></progress>
Would it be possible to link the progress bar so that when i play a song the progress is shown?
Yes, it is possible using the timeupdate event of the audio tag. You receive this event every time the position of the playback is updated. Then, you can update your progress bar using the currentTime and duration properties of the audio element.
You can see a working example in this fiddle
If you want smooth progress bar,try somethink like that
HTML:
<div class="hp_slide">
<div class="hp_range"></div>
</div>
CSS:
.hp_slide{
width:100%;
background:white;
height:25px;
}
.hp_range{
width:0;
background:black;
height:25px;
}
JS:
var player = document.getElementById('player');
player.addEventListener("timeupdate", function() {
var currentTime = player.currentTime;
var duration = player.duration;
$('.hp_range').stop(true,true).animate({'width':(currentTime +.25)/duration*100+'%'},250,'linear');
});
Pretty rough,but works
Here's a simple vanilla example:
const url = "https://upload.wikimedia.org/wikipedia/en/a/a9/Webern_-_Sehr_langsam.ogg";
const audio = new Audio(url);
const playBtn = document.querySelector("button");
const progressEl = document.querySelector('input[type="range"]');
let mouseDownOnSlider = false;
audio.addEventListener("loadeddata", () => {
progressEl.value = 0;
});
audio.addEventListener("timeupdate", () => {
if (!mouseDownOnSlider) {
progressEl.value = audio.currentTime / audio.duration * 100;
}
});
audio.addEventListener("ended", () => {
playBtn.textContent = "▶️";
});
playBtn.addEventListener("click", () => {
audio.paused ? audio.play() : audio.pause();
playBtn.textContent = audio.paused ? "▶️" : "⏸️";
});
progressEl.addEventListener("change", () => {
const pct = progressEl.value / 100;
audio.currentTime = (audio.duration || 0) * pct;
});
progressEl.addEventListener("mousedown", () => {
mouseDownOnSlider = true;
});
progressEl.addEventListener("mouseup", () => {
mouseDownOnSlider = false;
});
button {
font-size: 1.5em;
}
<button>▶️</button>
<input type="range" value="0" min="0" max="100" step="1">
The approach is to use an input[type="range"] slider to reflect the progress and allow the user to seek through the track. When the range changes, set the audio.currentTime attribute, using the slider as a percent (you could also adjust the max attribute of the slider to match the audio.duration).
In the other direction, I update the slider's progress on timeupdate event firing.
One corner case is that if the user scrolls around with their mouse down on the slider, the timeupdate event will keep firing, causing the progress to hop around between wherever the user's cursor is hovering and the current audio progress. I use a boolean and the mousedown/mouseup events on the slider to prevent this from happening.
See also JavaScript - HTML5 Audio / custom player's seekbar and current time for an extension of this code that displays the time.
First of all, don't use the progress element, it's a shitty element (for now) and styling it is a huge pain in... well it's boring (look at a little project I made, look at it (and it's juste webkit/moz)).
Anyway, you should read the doc on MDN, it's very easy and with a lot of examples. What you are looking for is the currentTime attribute, here a little snippet :
var audio = document.querySelector('#player')
audio.currentTime = 60 // will go to the 60th second
So what you need is to use the cross-multiplication (div is the element you use as a progress bar) :
Where I clicked on div | THE TIME I WANT TO KNOW
————————————————————————————————————————
Total length of div | The total time of my video/audio (audio.seekable.end())

Categories

Resources