I'm running into some issues writing an app using the Web Audio API.
I'm trying to play multiple sounds with Web Audio API, each with an individual volume control and able to have multiple different sounds playing at once., but I can't figure out how to implement it.
I can figure out how to implement a universal volume control, but would like to be able to increase/decrease individual sounds. I am also having the issue that when I have multiple sounds playing, I can't seem to stop them all.. one sounds seems to always get stuck somewhere.
Any advise on how to update the below code would be greatly appreciated.
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/loopy_styles.css" />
<script>
context = new (window.AudioContext || window.webkitAudioContext)();
//We set up an array of buffers to store our sounds in, with an extra entry as dummy '0' entry
var soundBuffers = [null,null,null,null,null,null];
//We load our sounds into the buffer when the page is opened.
window.onload = function() {
loadSound('sounds/fire_test1.wav', 1);
loadSound('sounds/wind_test.wav', 2);
loadSound('sounds/rain_test1.wav', 3);
loadSound('sounds/stream.mp3', 4);
loadSound('sounds/spring_test.wav', 5);
};
var currentlyPlayingSoundNum = 0;
var currentlyPlayingSound = null;
//Function to play sound, take in a number to represent each sound icon.
function play_sound(num){
if (num) {
//Shows the paused version of button, hides the play version of the button.
document.getElementById('playBtn'+num+'_play').style.display = 'none';
document.getElementById('playBtn'+num+'_stop').style.display = 'block';
//Sets the currently playing sound to the number supplied to the function.
currentlyPlayingSoundNum = num;
//Creates buffer for sound.
currentlyPlayingSound = context.createBufferSource();
//Sets the sound to loop continuously so we have seemless play-back.
currentlyPlayingSound.looping = true;
//Sends the sound at spot num in our buffer array to the buffer for our currently playing sound.
currentlyPlayingSound.buffer = soundBuffers[num];
currentlyPlayingSound.connect(context.destination);
//Start playing the sound.
currentlyPlayingSound.start(0);
}
}
//Function to stop sound, take in a number to represent each sound icon.
function stop_sound(num){
if(num){
document.getElementById('playBtn'+num+'_play').style.display = 'block';
document.getElementById('playBtn'+num+'_stop').style.display = 'none';
}
if (currentlyPlayingSound) {
//Shows the play version of button, hides the paused version of the button.
document.getElementById('playBtn'+currentlyPlayingSoundNum+'_play').style.display = 'block';
document.getElementById('playBtn'+currentlyPlayingSoundNum+'_stop').style.display = 'none';
//Stops playing the currently playing sound.
currentlyPlayingSound.stop(0);
currentlyPlayingSound = null;
currentlyPlayingSoundNumber = 0;
}
}
function loadSound(url, bufferNum) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onload = function() {
var successCallback = function(buffer) {
soundBuffers[bufferNum] = buffer;
}
var errorCallback = function(e) {
console.log(e);
}
context.decodeAudioData(request.response, successCallback, errorCallback);
}
request.send();
}
</script>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<title>Ambient Sound Generator</title>
</head>
<body>
<div class="background">
<div id="intro-text">
<h1 id="site-title">Ambient Sound Generator</h1>
<p>Mix ambient sounds together to block out distractions and help you focus or relax</p>
<p>Click the buttons below to begin</p>
</div>
<div id="button-container">
<div id="btn1">
<input type="image" class="pp_img" src="img/fire-pause.png" name="Fire" id="playBtn1_play" onclick="play_sound(1);" />
<input type="image" class="pp_img" src="img/fire-play.png" name="Fire" id="playBtn1_stop" onclick="stop_sound(1);" style="display:none" />
<p><input type="range" min="0" max="100" value="100" onchange="sample.changeVolume();">Volume</p>
</div>
<div id="btn2">
<input type="image" class="pp_img" src="img/wind-pause.png" name="Wind" id="playBtn2_play" onclick="play_sound(2);" />
<input type="image" class="pp_img" src="img/wind-play.png" name="Wind" id="playBtn2_stop" onclick="stop_sound(2);" style="display:none" />
<p><input type="range" min="0" max="100" value="100" onchange="sample.changeVolume();">Volume</p>
</div>
<div id="btn3">
<input type="image" class="pp_img" src="img/rain-pause.png" name="Rain" id="playBtn3_play" onclick="play_sound(3);"/>
<input type="image" class="pp_img" src="img/rain-play.png" name="Rain" id="playBtn3_stop" onclick="stop_sound(3);" style="display:none"/>
<p><input type="range" min="0" max="100" value="100" onchange="sample.changeVolume();">Volume</p>
</div>
<div id="btn4">
<input type="image" class="pp_img" src="img/stream-pause.png" name="Stream" id="playBtn4_play" onclick="play_sound(4);"/>
<input type="image" class="pp_img" src="img/stream-play.png" name="Stream" id="playBtn4_stop" onclick="stop_sound(4);" style="display:none"/>
<p><input type="range" min="0" max="100" value="100" onchange="sample.changeVolume();">Volume</p>
</div>
<div id="btn5">
<input type="image" class="pp_img" src="img/forest-pause.png" name="Rain" id="playBtn5_play" onclick="play_sound(5);"/>
<input type="image" class="pp_img" src="img/forest-play.png" name="Rain" id="playBtn5_stop" onclick="stop_sound(5);" style="display:none" />
<p><input type="range" min="0" max="100" value="100" onchange="sample.changeVolume();">Volume</p>
</div>
</div>
</div>
</body>
<script>
function refreshData(){
x = 1; // x = seconds
var d = new Date()
var h = d.getHours();
var m = d.getMinutes();
var s = d.getSeconds();
if (h<=9) {h = '0'+h};
if (m<=9) {m = '0'+m};
if (s<=9) {s = '0'+s};
var color = '#'+h+m+s;
$("div.background").css("background-color", color );
$("p#hex").text(color);
setTimeout(refreshData, x*1000);
}
refreshData(); // execute function
</script>
Instead of
currentlyPlayingSound.connect(context.destination);
You just need to create another GainNode and chain it in:
var gain = context.createGain();
gain.gain.value = /*insert your gain variable here */;
currentlyPlayingSound.connect(gain);
gain.connect(context.destination);
You'll probably want to cache the gain node somewhere (so you can have a slider, etc.)
Related
I would like for the code to change its answer when I change the value of the input.
So let's say instead of 10, I would like it to tell me how much HP (health points) I will have at level 15. Is there any way I can do this? I'm not that experienced in Javascript.
So right now I coded it to default to 10 on all stats. My website tells me that at level 10, I have 895.4 hp. The only problem is that it won't stay at 15 when I try to press enter. It will just revert back to 10. Pretty much useless. Is there any way to keep that number 15 when I press enter?
var finalhp = 500;
let hpmultiplier = 1.06;
var hpvaluestring = document.querySelector('.hp').value;
var hpvalue = parseInt(hpvaluestring);
for (let i = 0; i < hpvalue; i++) {
var finalhp = finalhp * hpmultiplier
}
console.log(finalhp)
<form>
<div>
<input class="hp" id="amount" type="number" value="10" min="0" max="50" oninput="rangeInput.value=amount.value">
<input class="slider" id="rangeInput" type="range" value="10" min="0" max="50" oninput="amount.value=rangeInput.value">
</div>
</form>
Add a form submit event listener to the form element and prevent form submission there.
<form onsubmit="submitForm(event)">
<div>
<input class="hp" id="amount" type="number" value="10" min="0" max="50" oninput="rangeInput.value=amount.value">
<input class="slider" id="rangeInput" type="range" value="10" min="0" max="50" oninput="amount.value=rangeInput.value">
</div>
</form>
Add a submitForm function inside a script tag
function submitForm(event){
event.preventDefault();
var finalhp = 500;
let hpmultiplier = 1.06;
var hpvaluestring = document.querySelector('.hp').value;
var hpvalue = parseInt(hpvaluestring);
for (let i = 0; i < hpvalue; i++) {
var finalhp = finalhp * hpmultiplier
}
console.log(finalhp)
}
So mainly I'm just adding eventListeners to trigger the function calculateHP on input/slider value change. The function calculateHP contains the same logic that you shared. I did this so that the eventListeners can callback the function.
Try the following:
const input = document.querySelector('.hp')
const slider = document.querySelector('.slider')
slider.addEventListener('change', calculateHP)
input.addEventListener('change', calculateHP)
function calculateHP(){
let multiplier = 1.06
let level = Number(input.value)
let HP = 500
for(let i = 0; i<level; i++){
HP = HP * multiplier
}
return console.log(HP)
}
<div>
<label>Level: </label>
<input class="hp" id="amount" type="number" value="10" min="0" max="50" oninput="rangeInput.value=amount.value">
<input class="slider" id="rangeInput" type="range" value="10" min="0" max="50" oninput="amount.value=rangeInput.value">
</div>
I am trying to implement two sliders in HTML and use Javascript functions to update the indicator of the values of those sliders. I don't know how to structure the code for the output of each slider. I think there is a problem with the way that the Javascript codes are embedded. Does anyone know how I can solve this issue?
Purpose: Have two sliders with two separate indicators in HTML
Thanks!
<body>
<h1>Round Range Slider</h1>
<div class="slidecontainer">
<input type="range" min="1" max="100" value="50" class="slider" id="myRange">
<p>Value: <span id="demo"></span></p>
</div>
<div class="slidecontainer">
<input type="range" min="1" max="100" value="50" class="slider" id="myRange1">
<p>Value1: <span id="demo1"></span></p>
</div>
</body>
<head>
<script>
var slider = document.getElementById("myRange");
var output = document.getElementById("demo");
output.innerHTML = slider.value;
slider.oninput = function() {
output.innerHTML = this.value;
}
</script>
<script>
var slider = document.getElementById("myRange1");
var output = document.getElementById("demo1");
output.innerHTML = slider.value;
slider.oninput = function() {
output.innerHTML = this.value;
}
</script>
</head>
Duplicating the code, taking into account the introduction of small changes - is bad.
I made you a js code with the forEach() method. This means that now you can control many input without having to write js logic for every.
Just replace your js code with this one:
let input = document.querySelectorAll('.slidecontainer input');
let result = document.querySelectorAll('.slidecontainer span');
input.forEach(function(input_current, index) {
input_current.oninput = function() {
result[index].innerHTML = this.value;
}
});
Declaring variables in separate script tags does not create two copies of the variable. You can declare a variable for each slider by giving them different names.
<body>
<h1>Round Range Slider</h1>
<div class="slidecontainer">
<input type="range" min="1" max="100" value="50"
class="slider" id="myRange">
<p>Value: <span id="demo"></span></p>
</div>
<div class="slidecontainer">
<input type="range" min="1" max="100" value="50"
class="slider" id="myRange1">
<p>Value1: <span id="demo1"></span></p>
</div>
</body>
<head>
<script>
var slider = document.getElementById("myRange");
var output = document.getElementById("demo");
output.innerHTML = slider.value;
slider.oninput = function() {
output.innerHTML = this.value;
}
var slider1 = document.getElementById("myRange1");
var output1 = document.getElementById("demo1");
output1.innerHTML = slider1.value;
slider1.oninput = function() {
output1.innerHTML = this.value;
}
</script>
</head>
Better yet, use a loop:
<body>
<h1>Round Range Slider</h1>
<div class="slidecontainer">
<input type="range" min="1" max="100" value="50"
class="slider" id="myRange">
<p>Value: <span id="demo"></span></p>
</div>
<div class="slidecontainer">
<input type="range" min="1" max="100" value="50"
class="slider" id="myRange1">
<p>Value1: <span id="demo1"></span></p>
</div>
</body>
<head>
<script>
let sliders = document.querySelectorAll(".slidecontainer");
sliders.forEach(slideContainer => {
// Get a reference to the children of the current container.
let sliderChild = slideContainer.children[0];
let spanChild = slideContainer.children[1].children[0];
// Attach an event listener to each slider.
sliderChild.oninput = () => spanChild.innerText = sliderChild.value;
// Initialize the label.
spanChild.innerText = sliderChild.value;
});
</script>
</head>
Can you please help me how to get values of a range slider in javascript?
<script>
$(function()
{
$('.slider').on('input change', function(){
$(this).next($('.slider_label')).html(this.value);
});
$('.slider_label').each(function(){
var value = $(this).prev().attr('value');
$(this).html(value);
});
})
</script>
<p><label for="range_size">Size: </label> <input type="range" name="size" class="slider" min="1" max="75" value="45">
<span class="slider_label"></span></p>
<p><label for="range_width">Width: </label> <input type="range" name="width" class="slider" min="1" max="6" value="1">
<span class="slider_label"></span></p>
I am trying to get like this :
<script type="text/javascript">
function calculate () {
var size = document.getElementById ("size").value;
alert(size);
</script>
But it doesn't show any alert. Can you please help me?
Using value does work :
let p = document.getElementById("val")
let range = document.getElementById("slide")
let changeVal = () => {
p.textContent = range.value
}
changeVal()
range.onchange = changeVal
<input id="slide" type="range" min="0" max="100"/><p id="val"></p>
as B001ᛦ said in comment the problem is you forgot to add an id on your <input>
If you prefer you can also use names but you need to take care as name can be reused while Ids are unique
let p = document.getElementsByName("val")[0]
let range = document.getElementsByName("slide")[0]
let changeVal = () => {
p.textContent = range.value
}
changeVal()
range.onchange = changeVal
<input name="slide" type="range" min="0" max="100"/><p name="val"></p>
getElementsByName return a NodeList so you'll need to get the node you need from this list (the first one if you have only one)
as a side note value does exists on every input type
I'm having an issue while designing a music player. My music player works with the following code:
playlist_index = 0;
// Set object references
playbtn = document.getElementById("playpausebtn");
seekslider = document.getElementById("seekslider");
volumeslider = document.getElementById("volumeslider");
curtimetext = document.getElementById("curtimetext");
durtimetext = document.getElementById("durtimetext");
playlist_status = document.getElementById("playlist_status");
playerImg = document.getElementById("playerImg");
// Audio Object
audio = new Audio();
audio.src = dir+playlist[0].song_url;
audio.loop = false;
playlist_status.innerHTML = playlist[playlist_index].song_name + '-' + playlist[playlist_index].band_name;
// Add Event Handling
playbtn.addEventListener("click",playPause);
mutebtn.addEventListener("click", mute);
seekslider.addEventListener("mousedown", function(event){ seeking=true; seek(event); });
seekslider.addEventListener("mousemove", function(event){ seek(event); });
seekslider.addEventListener("mouseup",function(){ seeking=false; });
volumeslider.addEventListener("mousemove", setvolume);
audio.addEventListener("timeupdate", function(){ seektimeupdate(); });
audio.addEventListener("ended", function(){ switchTrack(); });
audio.addEventListener("play", function(){ playbtn.style.background = "url(http://localhost/wordpress/wp-content/themes/virtue-child/pause.png) no-repeat"; });
// Functions
function switchTrack(){
if(playlist_index == (playlist.length - 1)){
playlist_index = 0;
} else {
playlist_index++;
}
playlist_status.innerHTML = playlist[playlist_index].song_name + '-' + playlist[playlist_index].band_name;
audio.src = dir+playlist[playlist_index].song_url;
setTimeout(audio.play(), 2000);
}
(plus some more functions for updating seek bars and times) and the following HTML:
<div id="audio_player">
<div id="playerImg"></div>
<div id="audio_controls">
<button id="playpausebtn"></button>
<p id="playlist_status"></p>
<div id="sliderHolder">
<input id="seekslider" type="range" min="0" max="100" value="0" step="1">
<span id="curtimetext">00:00</span>
<span id="durtimetext">00:00</span>
</div>
<button id="mutebtn"></button>
<br/>
<input id="volumeslider" type="range" min="0" max="100" value="100" step="1">
</div>
</div>
But when I start housing elements in container divs, the above code fails to update the time and the seek slider doesn't work. The housed and styled audio player HTML looks like this:
<div id="audio_player">
<img src="wp-content/uploads/band-photos/Logo.png" id="playerImg">
<p id="playlist_status"></p>
<div id="audio_controls">
<div id="sliderHolder">
<input id="seekslider" type="range" min="0" max="100" value="0" step="1">
<span id="curtimetext">00:00</span>
<span id="durtimetext">00:00</span>
</div>
<div id="musicButtons">
<button id="playpausebtn"></button>
<div id="volumeHolder">
<img src="http://localhost/wordpress/wp-content/themes/virtue-child/speaker.png" id="volButton">
<input id="volumeslider" type="range" min="0" max="100" value="100" step="1">
</div>
</div>
</div>
</div>
Is there an issue when I begin to house elements in divs and searching the DOM for them? Again, the JavaScript works with the first set of HTML, not the second.
Thank you everyone for the input. It looks like in styling the new player I removed the mute button. Therefore: 'mutebtn.addEventListener("click", mute);' was throwing an error and causing the rest of the functions not to work.
I'm not much of a javascript coder so i am seeking any advice from anyone who may be able to help me with a problem i have, the main issue is i am trying to swap an image so that they can be selected by choosing a radio button.
<script language="JavaScript">
function changeImage(newImage)
{
if document[imageName].src = eval(newImage + ".src");
}
var img00700000232 = new Image();
img00700000232.src = "/2/00700000232.jpg";
var img00700000263 = new Image();
img00700000263.src = "/2/00700000263.jpg";
var img00700000270 = new Image();
img00700000270.src = "/2/00700000270.jpg";
var img00700000133 = new Image();
img00700000133.src = "images/TempImage.png";
var img00700000164 = new Image();
img00700000164.src = "images/TempImage.png";
var img00700000140 = new Image();
img00700000140.src = "images/TempImage.png";
var img00700000157 = new Image();
img00700000157.src = "images/TempImage.png";
</script>
</head><body>
<form name="test">
<input name="field" type="radio" value="00700000232" onchange="changeImage('img00700000232');">Prod1</input>
<br/>
<input name="field" type="radio" value="00700000263" onchange="changeImage('img00700000263');">Prod2</input>
<br/>
<input name="field" type="radio" value="00700000270" onchange="changeImage('img00700000270');">Prod3</input>
<br/>
<input name="field" type="radio" value="00700000133" onchange="changeImage('img00700000133');">Prod4</input>
<br/>
<input name="field" type="radio" value="00700000164" onchange="changeImage('img00700000164');">Prod5</input>
<br/>
<input name="field" type="radio" value="00700000140" onchange="changeImage('img00700000140');">Prod6</input>
<br/>
<input name="field" type="radio" value="00700000157" onchange="changeImage('img00700000157');">Prod7</input>
<br/>
</form>
<img name="image_name" src="images/TempImage.png" />
This is the code that is generated from ASP classic so the code is generated server side so im not sure whether this is an issue or whether there is a problem with my code, any and all help will be much appreciated.
Thanks
Brad
You have a syntax error:
if document[imageName].src = eval(newImage + ".src");
should be:
if( document["image_name"])
document["image_name"].src = eval(newImage + ".src");
EDIT:
A better way to get at the "image_name" DOM element though would be to change the 'name' attribute to 'id' and use document.getElementById instead.
So, that'd look like this:
<img id="image_name" src="images/TempImage.png" />
function changeImage(newImage)
{
var imgEle = document.getElementById("image_name");
if (imgEle){
imgEle.src = eval(newImage + ".src");
}
}
Also, you don't necessarily need to use eval here. You can reference the image variables in the Anchor tag if you want
so change this
<input name="field" type="radio" value="00700000164" onchange="changeImage('img00700000164');">Prod5</input>
to this
Prod5
which you would then have to change your function from
function changeImage(newImage)
{
var imgEle = document.getElementById("image_name");
if (imgEle && newImage){
imgEle.src = newImage.src;
}
}