what does this javascript logic mean? - javascript

I can't wrap my head around this code from w3schools for a javascript play/pause event.
let video = document.getElementById("myVideo");
let btn = document.getElementById("myBtn");
function myFunc() {
if (video.paused) {
video.play();
btn.innerHTML = "Pause";
} else {
video.pause();
btn.innerHTML = "Play";
}
}
if the video paused is true then the video should play and the btn should display Pause. But shouldn't it be the other way round? If the video is paused then video.pause() should be there?

Remember, the action is performed when you click the button, so imagine if the video is playing and the function is executed, then the following snippet runs:
video.pause(); // the played video is now paused
btn.innerHTML = "Play"; // the button now shows 'Play' from what it was before 'Pause'
When the function is executed again (when it is paused) the code checks if it is paused and if it is then it means it needs to play hence the following snippet:
if (video.paused) { // Was the video paused? If yes...
video.play(); // We now play the video as it was paused
btn.innerHTML = "Pause"; // We changed the button text from 'Play' to 'Pause'
}
The comments in the above snippets should clarify further.

Related

How do I record musical notes as they are played with the Web Audio and Media Recorder api's?

I'm trying to create a little app that records sounds from audio nodes as they are played using the Web Audio API, but have run into a few problems.
I have two buttons ('start recording' & 'stop recording') a media recorder and a keydown event listener attached to the window.
I don't want to record through the device's speaker but directly from audioNodes
What I want to happen:
When I click the 'start recording' button, the media player should start recording (which it does)
When I press key "1" the function playNote should play a sound.
When I click the 'stop recording' button, the media player should stop recording.
When I click the 'play' button on the media player, it should play back the note, or notes that have been played.
What's actually happening so far:
Scenario 1:
Coded so the media player starts to record when the 'start recording' button is clicked
I press 'start recording' and the media player starts recording.
I press key "1" and the playNote function does not run, I can hear nothing through the speakers.
I click 'stop recording' and the media player stops recording.
I click the play button on the media player and the media plays back a silent recording that lasts for the duration of the recorded session.
Result: The media recorder didn't record my sound!
Scenario 2:
Coded so the media recorder starts recording when the playNote function runs:
I press key "1" and the note plays and the media recorder starts recording.
I click the 'stop recording' button and the media player stops recording.
I click the play button on the media player and the recording is played back.
My problem with this second scenario is that I want to play more than one note/sound with successive keystrokes throughout the duration of the recording period so, starting the startRecording function in my playNote function does not achieve this, because as soon as key "1" is pressed again, a new sound and new recording session are started.
So what I actually want to happen is this:
Scenario 3:
Coded so the media recorder starts recording when the 'start recording' button is clicked:
I click the 'start recording' button and the media player starts a recording session.
I press key "1" a few times, the notes played and recorded
I click the 'stop recording' button and the media player stops recording.
I click the play button on the media player and the recording is played back with all notes present
If anyone can help me solve this problem, I would be very grateful. The only way I can imagine getting this to work at the moment is to somehow create a Blob of each sound played and then chain them all together by pushing them into an array to play back the final recording.
What I'm wondering is, is there a way to inject (for want of another term) outputs from audioNodes into an already running media stream? It would make life so much simpler! :-)
The code I have so far is below. If you comment out this line:
startRecording(); // If this isn't here, the note doesn't play when the media player has been told to start recording
You can see how Scenario 1 pans out, as described above.
Thanks for taking the time to look at this.
// Variables
let audioTag = document.getElementById("audioTag"),
started = false,
stopped,
startBtn = document.getElementById("startBtn"),
stopBtn = document.getElementById("stopBtn"),
actx,
recorder = false,
recordingStream = false,
mainVol;
// Define the global context, recording stream & gain nodes
actx = new AudioContext();
recordingStream = actx.createMediaStreamDestination();
mainVol = actx.createGain();
mainVol.gain.value = 0.1;
// Connect the main gain node to the recording stream and speakers
mainVol.connect(recordingStream);
mainVol.connect(actx.destination);
// Function to run when we want to start recording
function startRecording() {
recorder = new MediaRecorder(recordingStream.stream);
recorder.start();
started = true;
}
// Function to run when we want to terminate the recording
function stopRecording() {
recorder.ondataavailable = function(e) {
audioTag.src = URL.createObjectURL(e.data);
recorder = false;
stopped = true;
};
recorder.stop();
}
// Event listeners attached to the start and stop buttons
startBtn.addEventListener(
"click",
(e) => {
e.target.disabled = true;
console.log("start button clicked");
startRecording();
},
false
);
stopBtn.addEventListener("click", (e) => {
console.log("stop button clicked");
startBtn.disabled = false;
stopRecording();
});
// A function to play a note
function playNote(freq, decay = 1, type = "sine") {
let osc = actx.createOscillator();
osc.frequency.value = freq;
osc.connect(mainVol); // connect to stream destination via main gain node
startRecording(); // // If this isn't here, the note doesn't play when the media player has been told to start recording
console.log(mainVol);
osc.start(actx.currentTime);
osc.stop(actx.currentTime + 1);
}
// keydown evennt listener attached to the window
window.addEventListener("keydown", keyDownHandler, false);
// The keydown handler
function keyDownHandler(e) {
if (e.key === "1") {
console.log(e.key, "pressed");
playNote(440);
}
}
<p>
<button id="startBtn">Start Recording</button>
<button id="stopBtn">Stop Recording</button>
</p>
<audio id="audioTag" controls="true"></audio>
OK! After a few days of unsuccessful research and hair loss, I had a thought! I have them occasionally ::oP
If we look at the code above we can see that we are creating a new MediaRecorder every time the startRecording function is called:
function startRecording() {
recorder = new MediaRecorder(recordingStream.stream);
recorder.start();
started = true;
}
So I thought:
pull the recorder constructor out into the global scope
get rid of the recorder = false when stopRecording is called, so we can record again using the same MediaRecorder again if we wish:
function stopRecording() {
recorder.ondataavailable = function(e) {
audioTag.src = URL.createObjectURL(e.data);
//recorder = false;
stopped = true;
};
recorder.stop();
}
Then, in our playNote function, add a conditional statement to only start the MediaRecorder if it is not already recording:
function playNote(freq, decay = 1, type = "sine") {
let osc = actx.createOscillator();
osc.frequency.value = freq;
osc.connect(mainVol); // connect to stream destination via main gain node
// Only start the media recorder if it is not already recording
if (recorder.state !== "recording") {
startRecording();
} // If this isn't here, the note doesn't play
console.log(mainVol);
osc.start(actx.currentTime);
osc.stop(actx.currentTime + decay);
}
This works :-)
I also removed the startBtn and its event listener so that we don't accidentally press it and overwrite our recording.
And just for fun, added a new note to our keyDownHandler
function keyDownHandler(e) {
if (e.key === "1") {
console.log(e.key, "pressed");
playNote(440);
}
if (e.key === "2") {
playNote(600);
}
}
The final result is that we can now play notes repeatedly, stop recording when we are finished by clicking the stopBtn and then play back the recording by clicking the play button on the media recorder.
Here's a working snippet:
// Variables
let audioTag = document.getElementById("audioTag"),
started = false,
stopped,
// startBtn = document.getElementById("startBtn"),
stopBtn = document.getElementById("stopBtn"),
actx,
recorder = false,
streamDest = false,
mainVol;
// Define the global context, recording stream & gain nodes
actx = new AudioContext();
streamDest = actx.createMediaStreamDestination();
mainVol = actx.createGain();
mainVol.gain.value = 1;
// Create a new MediaRecorder and attached it to our stream
recorder = new MediaRecorder(streamDest.stream);
// Connect the main gain node to the recording stream and speakers
mainVol.connect(streamDest);
mainVol.connect(actx.destination);
// Function to run when we want to start recording
function startRecording() {
recorder.start();
started = true;
console.log(recorder.state);
}
// Function to run when we want to terminate the recording
function stopRecording() {
recorder.ondataavailable = function(e) {
audioTag.src = URL.createObjectURL(e.data);
// recorder = false;
stopped = true;
};
recorder.stop();
}
// Event listeners attached to the start and stop buttons
// startBtn.addEventListener(
// "click",
// (e) => {
// e.target.disabled = true;
// console.log("start button clicked");
// startRecording();
// },
// false
// );
stopBtn.addEventListener("click", (e) => {
console.log("stop button clicked");
// startBtn.disabled = false;
stopRecording();
});
// A function to play a note
function playNote(freq, decay = 1, type = "sine") {
let osc = actx.createOscillator();
osc.frequency.value = freq;
osc.connect(mainVol); // connect to stream destination via main gain node
// Only start the media recorder if it is not already recording
if (recorder.state !== "recording") {
startRecording();
}
osc.start(actx.currentTime);
osc.stop(actx.currentTime + decay);
}
// keydown evennt listener attached to the window
window.addEventListener("keydown", keyDownHandler, false);
// The keydown handler
function keyDownHandler(e) {
if (e.key === "1") {
console.log(e.key, "pressed");
playNote(440);
}
if (e.key === "2") {
playNote(600);
}
}
* {
margin: 0;
padding: 4px;
}
<h6>Keys #1 & #2 play sounds</h6>
<p>Recording starts when the first key is pressed</p>
<h6>Press the 'Stop Recording' button when finished</h6>
<h6>
Click the play button on the media recorder to play back the recording
</h6>
<p>
<!-- <button id="startBtn">Start Recording</button> -->
<button id="stopBtn">Stop Recording</button>
</p>
<audio id="audioTag" controls="true"></audio>
So in the end, all we needed to do was:
create the MediaRecorder in the global scope
Start the MediaRecorder only if it is not already recording.

Reset button text after audio plays

I have a button that plays an audio file when you click playAudio with the text "PLAY VOICE AUDIO", and the text is changed to "PAUSE VOICE". It pauses if you click playAudio again(now with the text "PAUSE VOICE") when playing.
I would like the button text to go back to the "PLAY VOICE AUDIO" once the audio file has finished playing.
Thanks for any help in advance!
<div class="center">
<button id="playAudio">PLAY VOICE AUDIO</button>
</div>
<audio id="testAudio" hidden src="testaudioagainmp3.mp3" type="audio/mpeg"></audio>
<!-- Play/pause audio script -->
<script>
document.getElementById("playAudio").addEventListener("click", function() {
var audio = document.getElementById('testAudio');
if(this.className == 'is-playing') {
this.className = "";
this.innerHTML = "PLAY VOICE AUDIO"
audio.pause();
} else {
this.className = "is-playing";
this.innerHTML = "PAUSE VOICE";
audio.play();
}
});
</script>
var audio = document.getElementById('testAudio');
var btn = document.getElementById("playAudio");
audio.addEventListener('ended', function() {
btn.innerHTML = "PLAY VOICE AUDIO";
btn.className = "";
});
You are currently only have an event listener for clicks on your button playAudio. You need a second event listener for when the audio has ended playing. In this case it is simply the ended event, which you need to attach to your audio variable with addEventListener.
Below is the the code I would use.
// This part is just a refactored version of your current code.
var audio = document.getElementById('testAudio');
var playButton = document.getElementById('playAudio');
playButton.addEventListener('click', function() {
if(this.className == 'is-playing') {
this.className = "";
this.innerHTML = "PLAY VOICE AUDIO"
audio.pause();
} else {
this.className = "is-playing";
this.innerHTML = "PAUSE VOICE";
audio.play();
}
});
// This runs when the audio ends and will change the `playButton`'s text to be "PLAY VOICE AUDIO"
audio.addEventListener('ended', function() {
playButton.innerHTML = 'PLAY VOICE AUDIO';
playButton.className = '';
}
I would also suggest learning some ES6(the newest JavaScript version), but I have left the code as is.

Need to change the display name of multiple buttons with variables

I have a video that automatically starts playing. And I have a button:
<button onclick="playPause()">Play/Pause</button>
JS:
function playPause() {
if (myVideo.paused)
myVideo.play();
else
myVideo.pause();
}
And I want him to be named "Pause" when I open the page and he changes his name to "Play" when the video is paused and "Pause" when the video is being played.
I have this other button (similar to this one) that acts like this:
When the video is loaded the video window size is 480p and when I press the button "HD" it changes the video window size to 1280p and its own name to "SD" (for when I go to change back to 480p window) (user 1533609 ankit helped me here):
<button onclick="goHD(this)">HD</button>
JS:
function goHD(el) {
if (myVideo.width != 1280){
myVideo.width = 1280
el.innerHTML = "SD"
}
else{
myVideo.width = 720
el.innerHTML = "HD";
}
}
This is one is working great in my code but I don't see what I have to do to be able to do the exact same thing in the "Pause/play" button.
Any help is appreciated :)
Try
<button onclick="playPause(this)">Play/Pause</button>
And
function playPause(btn) {
if (myVideo.paused) {
myVideo.play();
btn.innerHTML = "play"
} else {
myVideo.pause();
btn.innerHTML = "pause"
}
}
See an example: https://jsfiddle.net/j82447k5/
Does it help you?
If you can use jquery, then you can change the button text easliy by using the text() function on this object which signifies the button.
If video is paused, then play it and change the text to Pause and vice verse. Updated code will be:
function playPause() {
if (myVideo.paused) {
myVideo.play();
$(this).text('Pause');
}
else{
$(this).text('Play');
myVideo.pause();
}
}
If you are using javascript only, then you can use textContent/innerText properties (browser-dependant):
Updated HTML:
<button type="button" onclick="playPause(this);">Play/Pause</button>
Updated JS:
function playPause(myBtn) {
if (myVideo.paused)
{
myVideo.play();
myBtn.innerHTML = "Pause";
}
else {
myVideo.pause();
myBtn.innerHTML = "Play";
}
}
See the fiddle: "https://jsfiddle.net/h7qb1b58/2/"

IE9 HTML5 video "play" event not fired on second play

I've built simple HTML5 video player. I'm having trouble with the "play" event not being fired in IE9. Have a look at the Fiddle.
The player has a big play button visible before playback, hidden while playing, visible when video completes.
Below are the three listeners I'm using.
btn.addEventListener("click", function() {
vid.play();
});
vid.addEventListener("play", function() {
btn.style.display = "none";
alert("'play' event fired");
});
vid.addEventListener("ended", function() {
btn.style.display = "block";
});
In IE9 the "play" event isn't being fired for the second and subsequent times the video is played through.
I'm guessing it's either something I don't understand about the "play" HTML5 video event, or some kind of bug in IE9.
Any help is greatly appreciated.
An assumption:: I think paused event remains false even when your video ends, so may be try explicitly setting pause once your video ends, as:
btn.addEventListener("click", function() {
vid.play();
});
vid.addEventListener("play", function() {
btn.style.display = "none";
alert("'play' event fired");
});
vid.addEventListener("ended", function() {
if( !this.paused ) this.pause();
btn.style.display = "block";
});

Display Message when <video> is finished

This might have been answered before but I have searched for hours and can't find anything without jquery on getting this to work and I don't really understand the bind method or how that works.
I just need my video to display a message once it is finished.
For some reason any time I try to use video.ended I get null back instead of true or false.
Also not sure why my setInterval is apparently wrong.
HTML:
<video id="videoAllUrBase" poster="images/all-ur-base-poster.png">
<source src="video/All Your Base Are Belong To Us.mp4" />
<source src="video/All Your Base Are Belong To Us.mp4.ogg" />
<source src="video/All Your Base Are Belong To Us.mp4.webm" />
<p>Your browsers does not support video</p>
</video>
<br></br>
<input id="playButton" type="button" onclick="playVideo();" value="Play" />
<input id="skipButton" type="button" onclick="skip(10);" value="Skip" />
<input id="rewButton" type="button" onclick="skip(-10);" value="Rewind" />
<p id="vidMessage">Click the Play button to start the video.</p>
JavaScript:
function playVideo(){
var video = document.getElementById('videoAllUrBase');
var message = document.getElementById('vidMessage');
var button = document.getElementById('playButton');
if(video.paused){
video.play();
button.value = "Pause";
message.innerHTML = "The video is playing, click the Pause button to pause the video.";
} else {
video.pause();
button.value = "Play";
message.innerHTML = "The video is paused, click the Play button to resume the video.";
}
}
function checkEnd{
var video = document.getElementById('videoAllUrBase');
var message = document.getElementById('vidMessage');
if(video.ended){
message.innerHTML = "The video has ended, click Play to restart the video.";
}
}
setInterval(checkEnd, 1000);
function skip(value) {
var video = document.getElementById("videoAllUrBase");
video.currentTime += value;
}
Instead of using setInterval to check for the video's status, listen for the ended event to know when it ends. Here's your code with the changes I'd use:
function playVideo() {
var video = document.getElementById('videoAllUrBase');
var message = document.getElementById('vidMessage');
var button = document.getElementById('playButton');
if (video.paused) {
video.play();
button.value = "Pause";
message.innerHTML = "The video is playing, click the Pause button to pause the video.";
} else {
video.pause();
button.value = "Play";
message.innerHTML = "The video is paused, click the Play button to resume the video.";
}
video.onended = videoEnded;
}
function videoEnded() {
var video = document.getElementById('videoAllUrBase');
var message = document.getElementById('vidMessage');
message.innerHTML = "The video has ended, click Play to restart the video.";
}
function skip(value) {
var video = document.getElementById("videoAllUrBase");
video.currentTime += value;
}
While it probably wouldn't affect your setup, it could be more useful to use addEventListener to bind the event.
References:
https://developer.mozilla.org/en-US/docs/DOM/Media_events
https://developer.mozilla.org/en-US/docs/DOM/EventTarget.addEventListener

Categories

Resources