I'm using the brilliant info on stories in flight to generate sound on mouseover events, its part of a project on digital writing. The draft I have currently keeps stopping sound, or in Chrome showing the 'Aw, Snap' page. The page is available at http://www.nathan-walker.co.uk/sounding
I've also upped the channels to 300 (which is potentially what i need). The other problem is I guess because i'm using WAV files and they're rather large! If someone could suggest alternatives or know some kind of workaround that would be great!
<audio id="multiaudio1" src="audio/flute_c_long_01.wav" preload="auto"></audio>
<audio id="multiaudio2" src="audio/piano_chord.wav" preload="auto"></audio>
<audio id="multiaudio3" src="audio/synth_vox.wav" preload="auto"></audio>
<audio id="multiaudio4" src="audio/shimmer.wav" preload="auto"></audio>
<audio id="multiaudio5" src="audio/sweep.wav" preload="auto"></audio>
Flute<br />
Piano Chord<br />
Synth Vox<br />
Shimmer<br />
Sweep<br />
<script type="text/javascript">
var channel_max = 10; // number of channels
audiochannels = new Array();
for (a=0;a<channel_max;a++) { // prepare the channels
audiochannels[a] = new Array();
audiochannels[a]['channel'] = new Audio(); // create a new audio object
audiochannels[a]['finished'] = -1; // expected end time for this channel
}
function play_multi_sound(s) {
for (a=0;a<audiochannels.length;a++) {
thistime = new Date();
if (audiochannels[a]['finished'] < thistime.getTime()) { // is this channel finished?
audiochannels[a]['finished'] = thistime.getTime() + document.getElementById(s).duration*1000;
audiochannels[a]['channel'].src = document.getElementById(s).src;
audiochannels[a]['channel'].load();
audiochannels[a]['channel'].play();
break;
}
}
}
First, 300 channels is very extreme for a web browser. You can crash it easily. Chrome set a lot of virtual memory paging (about 4x as much as my 2nd largest page), and crashed soon after.
Second, why use wavs? I would convert them into a compressed format and have the browser's player decompress it on the fly so you can save space.
Finally, instead of using the <audio> element (which is only designed for simple media playback), I would consider using the Web Audio API if possible - which it certainly is in the current Chrome and Safari versions. It's more performance modeled than the <audio> tag, which would be what you would be looking for in an experiment like this. It's not TERRIBLY difficult to use, as long as you follow the instructions. Here's a link to a tutorial.: http://creativejs.com/resources/web-audio-api-getting-started/
Related
On a WordPress website I want to add Rewind and Forward buttons to Audio Player to let forward and backward by 5 or 10 seconds. I've searched a lot and not found any information about it. Is it possible to do it?
I'd appreciate any clue or information.
It's very possible, you just have to make sure you are using the JavaScript Audio object that gives you access to the current time property that you can change to achieve this.
To initialize an audio track using this object
let myAudio = new Audio("audio source path");
To play the audio
myAudio.play()
To rewind by 5s
myAudio.currentTime -= 5
To fast forward by 5s
myAudio.currentTime += 5
If the standard HTML player is used for the audio, it is very simple to add additional buttons that control the video.
The <audio> and the <video> element expose their HTMLMediaElement API in JavaScript, which allows seeking to a certain time inside the video.
The following example is demonstrating these two buttons with 3s and a video, to make it more comprehensible with or without sound.
It is using the fastSeek() method, which might add a visual or audio seeking effect. If you want to be more precise in seeking, you should directly set v.currentTime += SKIP_s.
const SKIP_s = 3;
const v = document.querySelector('video');
const fw = document.getElementById('forward');
const rw = document.getElementById('rewind');
// actually forward or rewind
fw.addEventListener('click', () => v.fastSeek(v.currentTime + SKIP_s));
rw.addEventListener('click', () => v.fastSeek(v.currentTime - SKIP_s));
// only enable buttons when the video is ready
v.addEventListener('canplay', () => fw.disabled = false, rw.disabled = false);
video {
max-width: 100%;
}
<figure>
<video controls>
<source src="https://upload.wikimedia.org/wikipedia/commons/transcoded/8/87/Schlossbergbahn.webm/Schlossbergbahn.webm.1080p.vp9.webm" type="video/webm">
<p>Your browser does not seem to support WebM videos</p>
</video>
<button id="rewind" disabled>Rewind 3 s</button>
<button id="forward" disabled>Forward 3 s</button>
<figcaption>
A coach of the <span lang="de">Schlossbergbahn</span> in Graz, Austria, is mounting in its track up the mountain, passing the siding.
</figcaption>
</figure>
Of course, you could add logic to disable the buttons if they cannot seek + or - the intended step, but fastSeek() already takes care of limiting the time to the video’s duration. So a click might not actually forward or rewind 5 s, but only 2, which should be acceptable.
Customize the UI
This way you can set the buttons outside the native player’s user interface. If you wanted to present all control buttons in a coherent style, you could omit the controls attribute and implement your own toolbar.
Demo Video Licence
This video file is licenced under the Creative Commons Attribution 3.0 Austria license. Video Source
I'm working on a tour in webvr and using a-frame to build it. I have a bizarre problem. I seem to be able to get aframe to play a video inside a videosphere and correctly display every second of it the first time I enter a new scene, but whenever I exit from it and try to enter it again, only the sound works as supposed. I'm wondering if I'm doing something wrong in the loading of the video or something
I'm collecting the path to the video from a json file in which I describe what each rooms contains (they may have interactable pins for 16:9 video, images and the sort, and also pins that simply load a new scene).
After loading the json, I set the source of the videosphere, name image360, as such:
document.getElementById("image360").setAttribute('src', "#" + jsonArray.zones[zoneID].locations[locationID].name);
I then play the video using the following code :
video = document.querySelector('#' + jsonArray.zones[zoneID].locations[locationID].name);
video.muted = false;
video.addEventListener("ended", videoEnded);
video.play();
The event listener I add to the video takes care of taking the user back to the previous scene once the video ends, which I do using this code:
//This function is called immediately after the end of a 360 video. Thus it first starts by obtaining the scene it should load after the end of the scene
var thisEl = document.querySelector('#' + jsonArray.zones[zoneID].locations[locationID].name);
var currentLocation = jsonArray.zones[zoneID].locations[locationID];
var locationToReturnTo = currentLocation.locationToReturnTo;
var zoneToReturnTo = currentLocation.zoneToReturnTo;
//With the information obtained, the room is then loaded
generateRoom(zoneToReturnTo, locationToReturnTo);
//After loading the room, time to generate the correct pins
generatePins(zoneToReturnTo, locationToReturnTo);
I'm truly at a loss here, and have no idea why this doesn't work. I should note that javascript and aframe are not my area of expertise at all, I just had to pick up this project after a former colleague of mine, who was working on it, left the company abruptly, so excuse me if I'm making a basic mistake.
Thanks in advance.
Switching videos directly on a entity may not work properly:
document.querySelector("a-video").setAttribute("src", "vid.mp4")
because of the current tmp <video> handling.
You should try using the assets management system:
<a-assets>
<video id="vid" src="derby.mp4"></video>
</a-assets>
<!-- Scene. -->
<a-plane src="#vid"></a-plane>
JS
(#vid).setAttribute("src", "newvid.mp4")
While having a video play through my local website, it's audio and video become de-synced after a while, like 40 minutes or so, also if I pause the video and then un pause it... I don't know if this is a problem with html 5, my browser, computer or what? But my audio is around 1 second ahead of the video, it's very noticeable... here's my code for the video in case it matters:
echo "<video class=\"videoContainer\" controls autoplay>
<source src=\"$movieUrl\" type=\"video/mp4\">
</video>";
I couldn't find any solution for this, in-fact... I couldn't find anyone with this same problem!
P.S Refreshing the page fixes the issue but I don't want to do that every time the video de-syncs... Also I don't have de-sync issues on YouTube etc...
There's currently no good API for synchronizing things with the timeline of a video, for instance captions or infoboxes. The spec has had "cue ranges" for this purpose earlier (which even earlier were "cue points"); it is expected that something similar will be added in the future, including support for declarative captions.
However, for now, you will have to either use a timer and read currentTime, or listen for timeupdate and read currentTime. timeupdate is fired at 15 to 250 ms intervals while the video is playing, unless the previous event handler for timeupdate is still running, in which case the browser should skip firing another event. Opera currently always fires it at 250 ms intervals while the video is playing, while Firefox currently fires it once per rendered frame. The idea is to allow the event to be fired at greater intervals if the system load increases, which could save battery life on a handheld device or keep things responsive in a heavy application. The bottom line is that you should not rely on the interval being the same over time or between browsers or devices.
Let's say you want to show a div element between the times 3s and 7s of the video; you could do it like this:
Hello world! var video = document.getElementsByTagName('video')[0]; var hello = document.getElementById('hello'); var hellostart = hello.getAttribute('data-starttime'); var helloend = hello.getAttribute('data-endtime'); video.ontimeupdate = function(e) { var hasHidden = hello.hasAttribute('hidden'); if (video.currentTime > hellostart && video.currentTime
The hidden attribute indicates that the element is not relevant and should be hidden. This is not supported in browsers yet, so you have to hide it with CSS:
*[hidden] { display:none }
The data-starttime and data-endtime attributes are custom data-* attributes that HTML5 allows to be placed on any element. It's great for including data that you want to read with script, instead of abusing the class or title atributes. HTML5 also has a convenience API for data-* attributes, but it's not supported in browsers yet, so we have to use getAttribute a little longer.
The above would look like this using a timer instead:
Hello world! var video = document.getElementsByTagName('video')[0]; var hello = document.getElementById('hello'); var hellostart = hello.getAttribute('data-starttime'); var helloend = hello.getAttribute('data-endtime'); setInterval(function() { var hasHidden = hello.hasAttribute('hidden'); if (video.currentTime > hellostart && video.currentTime
This will run every 100 ms. Whether you should use setInterval or timeupdate depends on what you're doing and whether you're ok with the interval changing. Note that the setInterval example above also runs when the video is not playing, which the timeupdate example doesn't. It's possible to clear the interval with clearInterval when the video stops playing and setting it again when it starts playing, though.
If you want to synchronize something with the time playback starts, or after a seek, you should listen for playing and seeked — not play or seeking. The former indicate when playback has actually started and a seek has finished, respectively, while the latter indicate that playback or seeking has just been requested, but could take some time before it actually occurs.
A notable issue that's appearing as I'm building a simple audio streaming element in HTML5 is that the <audio> tag doesn't behave as one would expect in regards to playing and pausing a live audio stream.
I'm using the most basic HTML5 code for streaming the audio, an <audio> tag with controls, the source of which is a live stream.
Current outcome: When the stream is first played, it plays whatever is streaming as expected. When it's paused and played again, however, the audio resumes exactly where it left off when the stream was previously paused. The user is now listening to a delayed version of the stream. This occurrence isn't browser-specific.
Desired outcome: When the stream is paused, I want the stream to stop. When it is played again, I want it resume where the stream is currently at, not where it was when the user paused the stream.
Does anyone know of a way to make this audio stream resume properly after it's been paused?
Some failed attempts I've made to fix this issue:
Altering the currentTime of the audio element does nothing to streaming audio.
I've removed the audio element from the DOM when the user stops stream playback and added it back in when user resumes playback. The stream still continues where the user left off and worse yet downloads another copy of the stream behind the scenes.
I've added a random GET variable to the end of the stream URL every time the stream is played in an attempt to fool the browser into believing that it's playing a new stream. Playback still resumes where the user paused the stream.
Best way to stop a stream, and then start it again seems to be removing the source and then calling load:
var sourceElement = document.querySelector("source");
var originalSourceUrl = sourceElement.getAttribute("src");
var audioElement = document.querySelector("audio");
function pause() {
sourceElement.setAttribute("src", "");
audioElement.pause();
// settimeout, otherwise pause event is not raised normally
setTimeout(function () {
audioElement.load(); // This stops the stream from downloading
});
}
function play() {
if (!sourceElement.getAttribute("src")) {
sourceElement.setAttribute("src", originalSourceUrl);
audioElement.load(); // This restarts the stream download
}
audioElement.play();
}
Resetting the audio source and calling the load() method seems to be the simplest solution when you want to stop downloading from the stream.
Since it's a stream, the browser will stop downloading only when the user gets offline. Resetting is necessary to protect your users from burning through their cellular data or to avoid serving outdated content that the browser downloaded when they paused the audio.
Keep in mind though that when the source attribute is set to an empty string, like so audio.src = "", the audio source will instead be set to the page's hostname. If you use a random word, that word will be appended as a path.
So as seen below, setting audio.src ="", means that audio.src === "https://stacksnippets.net/js". Setting audio.src="meow" will make the source be audio.src === "https://stacksnippets.net/js/meow" instead. Thus the 3d paragraph is not visible.
const audio1 = document.getElementById('audio1');
const audio2 = document.getElementById('audio2');
document.getElementById('p1').innerHTML = `First audio source: ${audio1.src}`;
document.getElementById('p2').innerHTML = `Second audio source: ${audio2.src}`;
if (audio1.src === "") {
document.getElementById('p3').innerHTML = "You can see me because the audio source is set to an empty string";
}
<audio id="audio1" src=""></audio>
<audio id="audio2" src="meow"></audio>
<p id="p1"></p>
<p id="p2"></p>
<p id="p3"></p>
Be aware of that behavior if you do rely on the audio's source at a given moment. Using the about URI scheme seems to trick it into behaving in a more reliable way. So using "about:" or "about:about", "about:blank", etc. will work fine.
const resetAudioSource = "about:"
const audio = document.getElementById('audio');
audio.src = resetAudioSource;
document.getElementById('p1').innerHTML = `Audio source: -- "${audio.src}"`;
// Somewhere else in your code...
if (audio.src === resetAudioSource){
document.getElementById('p2').innerHTML = "You can see me because you reset the audio source."
}
<audio id="audio"></audio>
<p id="p1"></p>
<p id="p2"></p>
Resetting the audio.src and calling the .load() method will make the audio to try to load the new source. The above comes in handy if you want to show a spinner component while the audio is loading, but don't want to also show that component when you reset your audio source.
A working example can be found here: https://jsfiddle.net/v2xuczrq/
If the source is reset using a random word, then you might end up with the loader showing up when you also pause the audio, or until the onError event handler catches it. https://jsfiddle.net/jcwvue0s/
UPDATE: The strings "javascript:;" and "javascript:void(0)" can be used instead of the "about:" URI and this seems to work even better as it will also stop the console warnings caused by "about:".
Note: I'm leaving this answer for the sake of posterity, since it was the best solution I or anyone could come up with at the time for my issue. But I've since marked Ciantic's later idea as the best solution because it actually stops the stream downloading and playback like I originally wanted. Consider that solution instead of this one.
One solution I came up with while troubleshooting this issue was to ignore the play and pause functions on the audio element entirely and just set the volume property of the audio element to 0 when user wishes to stop playback and then set the volume property back to 1 when the user wishes to resume playback.
The JavaScript code for such a function would look much like this if you're using jQuery (also demonstrated in this fiddle):
/*
* Play/Stop Live Audio Streams
* "audioElement" should be a jQuery object
*/
function streamPlayStop(audioElement) {
if (audioElement[0].paused) {
audioElement[0].play();
} else if (!audioElement[0].volume) {
audioElement[0].volume = 1;
} else {
audioElement[0].volume = 0;
}
}
I should caution that even though this achieves the desired functionality for stopping and resuming live audio streams, it isn't ideal because the stream, when stopped, is actually still playing and being downloaded in the background, using up bandwidth in the process.
However, this solution doesn't necessarily take up more bandwidth than just using .play() and .pause() on a streaming audio element. Simply using the audio tag with streaming audio uses up a great deal of bandwidth anyway, because once streaming audio is played, it continues to download the contents of the stream in the background when it is paused.
It should be noted that this method won't work in iOS because of purposefully built-in limitations for iPhones and iPads:
On iOS devices, the audio level is always under the user’s physical control. The volume property is not settable in JavaScript. Reading the volume property always returns 1.
If you choose to use the workaround in this answer, you'll need to create a fallback for iOS devices that uses the play() and pause() functions normally, or your interface will be unable to pause the stream.
Tested #Ciantics code and it worked with some modifications, if you want to use multiple sources.
As the source is getting removed, the HTML audio player becomes inactive, so the source (URL) needs to be added directly after again to become active.
Also added an event listener at the end to connect the function when pausing:
var audioElement = document.querySelector("audio");
var sources = document.querySelector("audio").children;
var sourceList = [];
for(i=0;i<sources.length;i++){
sourceList[i] = sources[i].getAttribute("src");
}
function pause() {
for(i=0;i<sources.length;i++){
sources[i].setAttribute("src", "");
}
audioElement.pause();
// settimeout, otherwise pause event is not raised normally
setTimeout(function () {
audioElement.load(); // This stops the stream from downloading
});
for(i=0;i<sources.length;i++){
if (!sources[i].getAttribute("src")) {
sources[i].setAttribute("src", sourceList[i]);
audioElement.load(); // This restarts the stream download
}
}
}
audioElement.addEventListener("pause", pause);
I am wondering how I make get an audio file to play 'continuously' on all pages. So if the audio file has played for 20 seconds, then when navigating on another page it will continue from where it left off. I also am trying to get the volume to decrease after navigating away from my home page. Any tips or advice would me appreciated! Thanks =D
<audio src="songforsite.mp3" loop="true" autoplay="true" controls>
Unsupported in Firefox
</audio>
Yes, it is possible. try this:
<audio preload="auto" src="a.mp3" loop="true" autobuffer>
Unsupported in Firefox
</audio>
<script>
function setCookie(c_name,value,exdays)
{
var exdate=new Date();
exdate.setDate(exdate.getDate() + exdays);
var c_value=escape(value) + ((exdays==null) ? "" : "; expires="+exdate.toUTCString());
document.cookie=c_name + "=" + c_value;
}
function getCookie(c_name)
{
var i,x,y,ARRcookies=document.cookie.split(";");
for (i=0;i<ARRcookies.length;i++)
{
x=ARRcookies[i].substr(0,ARRcookies[i].indexOf("="));
y=ARRcookies[i].substr(ARRcookies[i].indexOf("=")+1);
x=x.replace(/^\s+|\s+$/g,"");
if (x==c_name)
{
return unescape(y);
}
}
}
var song = document.getElementsByTagName('audio')[0];
var played = false;
var tillPlayed = getCookie('timePlayed');
function update()
{
if(!played){
if(tillPlayed){
song.currentTime = tillPlayed;
song.play();
played = true;
}
else {
song.play();
played = true;
}
}
else {
setCookie('timePlayed', song.currentTime);
}
}
setInterval(update,1000);
</script>
If you really navigate to another page, then you will not get really continuous playback.
There are three common approaches:
open your audio player in a popup
frames: one main frame for your page to display in, a small frame for the audio player
not really navigating to other pages, but do everything with AJAX and thereby not actually reloading the page, but only changing parts of the document structure dynamically; maybe adding real link functionality including changing the address bar by using the HTML5 History API
All approaches have their pros/cons. Popup is maybe the easiest to implement, and has the least drawbacks (compared to frames).
I also am trying to get the volume to decrease after navigating away from my home page.
Then catch any clicks on your “home” link/button, and call the volume method of the audio element with a parameter value ranging from 0 to 1 to set the volume.
well .. a clean and neat way to do it , is the way that soundcloud.com and spoify.com made through ajaxifing all the pages
fix a page and change the pages content through ajax ,and change the url as well to give the user the illusion of navigating
this is not the easiest or fastest solution ,but it's the cleanest one ..far away from the fear of browsers incompatibilities