Linking audio elements together HTML/AngularJS - javascript

I'm not entirely sure how to run a function that syncs up with the updating of a webpage.
I have a checkbox that runs a function if checked.
Html:
<input type="checkbox" value="data.id" id="status" ng-model="data.status" class="Form-label-checkbox" ng-change="IfCheck(data.Url)">
The IfCheck function adds the url into an array, $scope.ids
JavaScript: //kind of psuedocode
$scope IfCheck(url){
$scope.ids.push(object);}
$scope.Playall = function(){
var audioElements = document.getElementsByTagName("audio");
for(var i = 0; i < audioElements.length; i++){
audioElements[i].play();
}
}
This seems to work well so far. The array ids gets populated with the URLs on the fly. Afterwards, I run ng-repeat on this array, and create an element with the source as the url. This works as well.
HTML:
<div ng-repeat="data in ids">
<audio controls>
<source src="{{data.Url | trustUrl}}" id = "Synth.wav" type="audio/mpeg">
Your browser does not support the audio element.
</audio> </div>
My problem is this now. Lets say I check two boxes, and create two audio players on the fly. They play music if I click the play button. Is there a way to somehow make a button so that it will play both of them at the same time? I thought of something like
<button ng-click = "Playall()"> Playall </button>
but I'm not sure how to write the function to "link" to the created elements.

The Playall() function can look something like this:
$scope.Playall = function(){
Array.from(document.getElementsByTagName("audio")).forEach(audio => audio.play());
}
OR:
$scope.Playall = function(){
var audioElements = document.getElementsByTagName("audio");
for(var i = 0; i < audioElements.length; i++){
audioElements[i].play();
}
}

Related

I can't make a new Audio(url).play() to stop by new Audio(url).pause()

What I want to achieve: To stop a previously started sound when a new is started. What I have now: The sounds plays simultanously, none of them is stopping. The probably reason: Wrong logic statement in a line if (audio.played && audio.paused){. Before you judge me for not trying hard enough - I am trying to solve this from 3 days, I am a beginner. It should take me a few minutes, even an hour. I tried in several combinations.At the end I listed several websites which I tried and I still haven't solved it. In all answers is something similar but still I can't made a browser to chose, always only one part is executed either audio.play() or audio.pause() in the log. It works but not as I want and these logical statements are like on other informations on the forum. At the end of the message you can see all similar topics I already tried several times. I kept just as clear code as possible and I want to do it this way, in vanilla javascript because I won't deal for now with anything more complicated. An audio url is taken from modified id on click, the audios are on my disk. It works, I made some mistake in line if (audio.played && audio.paused){ Any ideas except giving up and changing a hobby?
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Timeout</title>
</head>
<script>
function playAudio3(clicked_id) {
var OriginalID = (clicked_id);
var res = OriginalID.slice(5,-1);
var audioID=res+'.mp3';
var url =audioID;
var audio = new Audio(url);
if (audio.played && audio.paused){
audio.play();
console.log('audio.play was used.');
}else {
audio.currentTime = 0
audio.pause();
console.log('audio.pause was used.');
}
}
</script>
<body>
<span id="guita2x"onclick="playAudio3(this.id);"> Guitar. </span>
<span id="piano2x" onclick="playAudio3(this.id);"> Piano. </span>
<span id="basse15x" onclick="playAudio3(this.id);"> Basse. </span>
</body>
</html>
how do i stop a sound when a key is released in JavaScript
Javascript Audio Play on click
Javascript to stop playing sound when another starts
HTML5 Audio stop function
cancel an if statement if another statement comes true
Stopping audio when another audio file is clicked using jQuery while obscuring link
https://www.w3schools.com/jsref/dom_obj_audio.asp
HTML5 Audio pause not working
Never give up, and don't change a hobby. :)
Possible solution from one hobbyist, too:
files = ['guitar', 'piano', 'bass']; // name of your files in array. You can get this array from looping through your html/spans id's too, but, this is basic logic
audios = []; //empty audios object array
for (i = 0; i < files.length; i++) {
var audioID = files[i] + '.mp3';
var url = audioID;
var audio = new Audio(url);
audios.push(audio); //place all audio objects into array
}
console.log(audios);
//now - basic logic to check which audio element to play, and to stop others
function playAudio3(clicked_id) {
for (i = 0; i < audios.length; i++) {
if (audios[i].src.includes(clicked_id)) {
audios[i].play();
} else {
audios[i].currentTime = 0
audios[i].pause();
}
}
}
So, you are creating all audio objects at the page load, and then choose which one to play. Of course, this will play all audio files from the start. If you want to keep the track of the audio progress, and play it from the last pause, you will need some additions, but, this could be the start, i hope.
OK, updated, i kept some of your code, and slightly changed some things in HTML.
Your complete code now should look like this: (HTML)
<span class='aud' id="guita1x" onclick="playAudio3(this.id);"> Guitar. </span>
<span class='aud' id="piano2x" onclick="playAudio3(this.id);"> Piano. </span>
<span class='aud' id="basse3x" onclick="playAudio3(this.id);"> Basse. </span>
Js:
spans=document.querySelectorAll('.aud');
console.log(spans);
audios = []; //empty audios object array
for (i = 0; i < spans.length; i++) {
var OriginalID = spans[i].id;
var res = OriginalID.slice(5,-1);
var audioID=res+'.mp3';
var url =audioID;
var audio = new Audio(url);
audios.push(audio); //place all audio objects into array
}
console.log(audios);
//now - basic logic to check which audio element to play, and to stop others
function playAudio3(clicked_id) {
for (i = 0; i < audios.length; i++) {
clickid=clicked_id.replace(/[A-Za-z]/g,'')+'.mp3';
if (audios[i].src.includes(clickid)) {
audios[i].play();
} else {
audios[i].currentTime = 0
audios[i].pause();
}
}
}
Now, i have just added class 'aud' to your spans, for easier targeting.
Then, i have collected id's from the spans and placed it in the audios array. (Not sure why you are slicing names/ids, you can simplify things by adding just numbers: 1, 2, 3 and so on).
NOW, this MUST work, IF
you have 3 .mp3 files in the same folder as your html/js file, called: 1.mp3, 2.mp3, 3.mp3.
if you place your javascript bellow HTML, BEFORE closing 'body' tag.

How to play a group of wav files with javascript

Let's say I have an Html file that look like this:
<div name="piano">
<div name="a.wav"></div>
<div name="b.wav"></div>
<div name="c.wav"></div>
</div>
How would I play all the .wav files mentioned in the piano div simultaneously (when a button is pressed)?
Edit: For clarification, eventually the user will be able to select what notes are played and at what time. This is just a simplified example.
The normal audio element (<audio> or new Audio()) is not appropriate for this use case, as it leaves no method for precise timing. You need to use the Web Audio API.
Use a BufferSourceNode for each note you want to play:
const buffer = await audioContext.decodeAudioData(... audio data ...);
const bufferSourceNode = audioContext.createBufferSource();
bufferSourceNode.buffer = buffer;
bufferSourceNode.connect(audioContext.destination);
bufferSourceNode.start(/* you can use a start time here */);
See also:
JSFiddle I made for a mini sampler: https://jsfiddle.net/bradisbell/sc9jpxvn/1/
AudioBufferSourceNode documentation: https://developer.mozilla.org/en-US/docs/Web/API/AudioBufferSourceNode
If you would like to play it randomly use:
<audio src="..." id="song1"></audio>
<audio src="..." id="song2"></audio>
<audio src="..." id="song2"></audio>
for(var i = 1; i <= 3; i++){
document.querySelector("#song" + i)[0].play();
}
With html5, you should use the <audio> tag. It have javascript hooks for 'play', 'pause', etc.
You can add the following html;
<button onclick="playA();playB();playC()">Play Audio</button>
with corresponding javascript
var audioA = new Audio('a.wav');
var audioB = new Audio('b.wav');
var audioC = new Audio('c.wav');
function playA() {
audioA.play();
}
function playB() {
audioB.play();
}
function playC() {
audioC.play();
}

Play different audio by clicking on class element

after many hours looking for a solution by myself, I'm asking for your help.
I'd like to play audio by clicking on an img and this is how I organised my code in HTML, audio will be different for each class : a_ru.mp3, b_ru.mp3 etc.
<span class="btn-audio-lexique">
<audio src="http://localhost/linguami-offline/fr/mp3/a_ru.mp3"></audio>
<img src="http://localhost/linguami-offline/img/circled-play.png">
</span>
<span class="btn-audio-lexique">
<audio src="http://localhost/linguami-offline/fr/mp3/b_ru.mp3"></audio>
<img src="http://localhost/linguami-offline/img/circled-play.png">
</span>
JS part which is unfortunately not workings looks like that
var classname = document.getElementsByClassName("btn-audio-lexique");
function playSound() {
var audio = classname.firstElementChild;
audio.play();
};
Array.from(classname).forEach(function(element) {
element.addEventListener('click', playSound);
});
I also tried with a for loop
for (var i = 0; i < classname.length; i++) {
classname[i].addEventListener('click', playSound);
}
console returns me a "audio is undefined error".
I would like to avoid creating a different id for all the audio in my page.
does anyone have an idea how should I organise my code for this works?
Thanks in advance !
You have few mistakes in your code:
I. Do not add event listener to each action element. It's bad for performance reasons. You should add event listener to some common parent element, which holds all the children buttons.
document.querySelector('.myAwesomeContainer').addEventListener('click', function(e) {
var target = e.target;
if (target && target.classList.contains('btn-audio-lexique')) {
var audio = target.firstElementChild;
// var audio = target.querySelector('audio');
if (audio) {
audio.play();
}
}
});
II. You don't necessarily need to mess up with audio elements. You can use AudioAPI and play sounds like:
var audio = new Audio('audio_file.mp3');
audio.play();
III. DO NOT use <span>, <div> or any HTML tag as clickable stuff except <button>, <a> Because you're destroing semantic markup and reducing accessability of you're application to the ground.
The actual reason of error in your current code, is hidden in that row:
var audio = classname.firstElementChild;
You're trying to get audio element not from the actual SPAN which user clicked, but from the array-like object of all your spans. Because classname is a LIST of all spans. What can you do in that situation? Just add event param to your playSound function. Because addEventListener will pass that param when event will be triggered:
var classname = document.getElementsByClassName("btn-audio-lexique");
function playSound(e) {
// Get actual clicked element
var target = e.target;
var audio = target.firstElementChild;
if (audio) {
audio.play();
}
};
Array.from(classname).forEach(function(element) {
element.addEventListener('click', playSound);
});

Alternating multiple video lists in html5 stored as javascript arrays

I have designed an i-phone-like screen on a web browser where I am testing this application I am in the process of building. It works great up until the point where I want to call out another set of videos.
What works
The application is structured so that when the user sees the screen she is directed to a channel that has a vertical video.
The buttons on the top left and top right advance to the next and the previous video.
<div id="topVid" class="videoContainer">
<div class="topHorizontalButtonRow">
</div>
<video class="topVid" loop onclick="this.paused? this.play() : this.pause()" >
<source src="videos/ParisisBurning_660x370_I_went_to_a_ball.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
There is a "channel" button that shows the user a smaller window if pressed, where the user can view other channels by clicking on a second set of buttons next and previous buttons.
<div id="bottomVid" class="videoContainerTwo hiddenElement">
<div class="topHorizontalButtonRow">
<div class="buttonLeftTriangleBlue"></div>
<div class="buttonRightTriangleBlue"></div>
</div>
<video loop onclick="this.paused? this.play() : this.pause()" >
<source src="videos/Politics_Refugee_Sign.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
jquery show/hide smaller window:
$(".buttonTeardropChannelBlue").click( function (){
if( $("#bottomVid").is(':visible') ) {
$("#bottomVid").hide();
} else {
$("#bottomVid").show();
}
});
If the user wants to watch this specific channel, she can click on the smaller window, which hides the current window and advances to the other channel. The video can be clicked on, and once that happens, the user will be directed to the next channel.
Below is the code that works perfectly to advance the video of the current selection, and it contains the videos in arranged in an array.
var Vids = (function() {
var _currentId = -1;
var _urls =
["videos/ParisisBurning_370x660_Get_Into_The_Suits_Vert.mp4","videos/ParisisBurning_370x660_School_Vert.mp4","videos/ParisisBurning_660x370_I_came_I_saw_Vert.mp4", "videos/ParisisBurning_660x370_I_went_to_a_ball.mp4"]; // literal array
return {
next: function() {
if (++_currentId >= _urls.length)
_currentId = 0;
return this.play(_currentId);
},
prev: function() {
if (--_currentId < 0)
_currentId = _urls.length - 1;
return this.play(_currentId);
},
play: function(id) {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = _urls[id];
myVideo.load();
myVideo.play();
return false;
}
}
})();
What does not work
The issue: showing and hiding multiple video lists
However, the problem starts when I want to select a different class of videos, which has the exact same code except for different videos. I have changed the name of the function to say, VidsTwo but the problem remains.
var VidsTwo = (function() {
var _currentId = -1;
var _urls = ["videos/Politics_Atl_We_are_the_people.mp4","videos/Politics_Atlanta_Whose_Streets.mp4", "videos/Politics_Womens_March_Washington_CBS_VERT.mp4",
"videos/Politics_No_bans_no_walls_America_is_home_to_all_VERT.mp4",
"videos/Politics_Let_them_in_VERT.mp4",
"videos/Politics_Tear it Down_JFK_VERT.mp4",
"videos/Politics_This_is_What_America_Looks_Like_embrace.mp4",
"videos/Politics_This_land_was_made_VERT.mp4", "videos/Politics_We_need_an_independent_investigation_town_hall.mp4",
"videos/Politics_Just say no_town_hall_VERT.mp4", ]; // literal array
return {
next: function() {
if (++_currentId >= _urls.length)
_currentId = 0;
return this.play(_currentId);
},
prev: function() {
if (--_currentId < 0)
_currentId = _urls.length - 1;
return this.play(_currentId);
},
play: function(id) {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = _urls[id];
myVideo.load();
myVideo.play();
return false;
}
}
})();
The issue remains: the buttons will continue to play the videos of the current channel in addition to the ones of the new channel, and it will not hide the current video. I understand it happens because in the javascript code, it uses the select element by tag which is "video". and all the array lists have "video" so it is playing all of them.
What is the best solution to this problem, given that I want to be able to separate the videos into categories "channels" that will have similar thematic content, and that this categories will be called by users as they look at a second smaller window of videos?
Core questions
Is there a way to have it NOT play a selection of arrays? What can I change in the Javascript code that will indicate that these separate video arrays do not belong to the same class? How can I make it clear in the code that these videos, although they are all videos, belong to different categories and therefore can only be played if their specific category is called?
Brainstorming solutions:
I am thinking I would probably need a second div that will have a
second row of buttons that call out the second function, since the
prev and next indicate a separate variable that was declared for each
class of videos...but this is getting a bit complicated for my newbie
skills:)
Or perhaps each video on a parent class should be saved on the
html itself as a hidden div and should be called by using "show
next child of parent div", as opposed to being saved as an array on
the javascript code?
The next step is adding marquee text to each video so maybe having
separate hidden divs on the html itself is a better solution than
having the videos stored as javascript arrays?
This is basically a prototype/beta for something that will become an
app so there is no database yet, (which will make it easier to
store this info eventually once I begin more in-depth user tests).
This complication is for testing only:)
UPDATE: I am still curious as to what the best solution would be, however I have decided, in this case, to add divs directly to the html and use jquery's next sibling selectors. Because I will have some text specific to some videos, they won't be properly connected to the javascript arrays anyway. I find the javascript array solution "cooler" but it is perhaps not the best in the end.
make Vids like this:
var Vids = function(vidArray=[]) {
var _currentId = -1;
var _urls = vidArray;
return {
next: function() {
if (++_currentId >= _urls.length)
_currentId = 0;
return this.play(_currentId);
},
prev: function() {
if (--_currentId < 0)
_currentId = _urls.length - 1;
return this.play(_currentId);
},
play: function(id) {
var myVideo = document.getElementsByTagName('video')[0];
myVideo.src = _urls[id];
myVideo.load();
myVideo.play();
return false;
}
}
};
then prepare your url array and call Vids:
var urls =["videos/ParisisBurning_370x660_Get_Into_The_Suits_Vert.mp4","videos/ParisisBurning_370x660_School_Vert.mp4","videos/ParisisBurning_660x370_I_came_I_saw_Vert.mp4", "videos/ParisisBurning_660x370_I_went_to_a_ball.mp4"];
Vids(urlf).play(3); //Replace 3 with any id

onPlay (or onClick?) Trigger Full Screen Video on iPad

Using the following HTML and JavaScript, I've been trying to trigger fullscreen video on the iPad. This works if there is only one video, but because there are numerous videos on the same page, only the first one works. I don't know how to separate out the videos so that they will all work properly. I've tried changing the IDs, and still, it doesn't work. Any advice would be greatly appreciated!
HTML:
<video id="test1" width="100%" height="200px" poster="http://www.example.com/wp-content/uploads/2013/12/example.png">
<source src="http://video.example.com/example.mp4" type="video/mp4">
</video>
<button id="test2">Play Video</button>
JavaScript:
<script type="text/javascript">
var video = document.getElementById('test1'),
play = document.getElementById('test2'),
time;
video.addEventListener('webkitbeginfullscreen', function() {
play.innerText = 'Play Video';
window.clearInterval(time);
});
video.addEventListener('webkitendfullscreen', function() {
video.pause();
});
play.addEventListener('touchstart', function() {
time = window.setInterval(function() {
try {
video.webkitEnterFullscreen();
}
catch(e) {}
}, 250);
play.innerText = 'loading ...';
video.play();
});
</script>
Without looking at the page that contains multiple videos, it's hard to know for sure. But it sounds like you may be using the #test1 and #test2 IDs in your HTML more than once, in which case document.getElementById('test1') would only return the first matching element on the page. Check out the result of what's being console'd out here: http://jsfiddle.net/tjnicolaides/q7Pyh/
Try using document.getElementsByTagName or document.getElementsByClassName and looping through the results to add your event listeners to each video on the page. Here's an example: http://jsfiddle.net/tjnicolaides/NDYkU/
var videos = document.getElementsByTagName('video'),
play_buttons = document.getElementsByClassName('play_button'),
time;
for(var i=0; i< videos.length; i++) {
// add event listeners and stuff here
}
for(var i=0; i < play_buttons.length; i++) {
// add event listeners and stuff here
}

Categories