Play loaded audio file with Tone.js web audio framework - javascript

Hi I'm creating a simple upload page where user load their local files and play it. For hour, i'm not uploading to the server, just want to create a file input and then play the audio file with Tone.js if it's possibel.
I'm using to this test P5.js library and Tone.js audio framework, the code below:
let inputFile, bttPlayFile;
let files;
window.AudioContext = window.AudioContext || window.webkitAudioContext;
let context = new Tone.Context();
let source;
function setup() {
inputFile = createFileInput(uploadTrack);
bttPlayFile = createButton('play');
bttPlayFile.mousePressed(tooglePlay);
}
function playSound(arraybuffer) {
context.decodeAudioData(arraybuffer, function(buf) {
source = new Tone.BufferSource();
source.connect(context).toDestinattion();
source.Tone.Buffer = buf;
source.start(0);
});
}
function selectedFile(evt) {
files = evt.target.files;
playFile(files[0]);
}
function playFile(file) {
let reader = new FileReader();
reader.onload = function(e) {
console.log(e.target.result);
playSound(e.target.result);
}
reader.readAsArrayBuffer(file);
}
function uploadTrack() {
inputFile.changed(selectedFile, false);
}
function tooglePlay() {
Tone.Transport.start();
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.32/Tone.js" integrity="sha512-USKCQh+O8BX/a2K06xPNTwduhmQvN/m9FhkR7PRysCRlPoqIItl7Qz3xVTZC/oIHe6g5XvnLHDUgGpRMZZTmFQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
At the moment, nothing happens and I want to understand why and how to proceed with this. Thanks!

If you open the console of your browser you should see a warning.
The AudioContext is "suspended". Invoke Tone.start() from a user
action to start the audio.
I think it will work if you call Tone.start() in the click handler of your "play" button before you load and decode the selected audio file.
It's unrelated to your question but it should be safe to remove window.AudioContext = window.AudioContext || window.webkitAudioContext from your code. Tone.js uses standardized-audio-context internally which should handle this for you.

Related

Javascript code runs fine on Codesandbox but not on localy or on a webserver

I tried to read read QR code thanks to javascript code found in this tutorial
The code provided by this tutorial works inside the codesandbox linked in the tutorial, however it doesn't work when I tired the same exact code on my laptop or on my remote webserver. I've litteraly copy and paste the code with the same file configuration, filenames ect... but I'm getting the following JS error on my browser :
SyntaxError: Identifier 'qrcode' has already been declared (at qrCodeScanner.js:1:1)
Since I run the exact same code I d'ont understand what is going on there. Is there something needed on the server side in order to make the code works that is not mentioned in the tutorial ?
If you want to see the code used and see it in action, you can teste the codesandbox instance there.
EDIT
Here's the code I use :
(HMTL)
<!DOCTYPE html>
<html>
<head>
<title>QR Code Scanner</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width; initial-scale=1.0, maximum-scale=1.0; user-scalable=0;" />
<link rel="stylesheet" href="./src/style.css" />
<script src="https://rawgit.com/sitepoint-editors/jsqrcode/master/src/qr_packed.js"></script>
</head>
<body>
<div id="container">
<h1>QR Code Scanner</h1>
<a id="btn-scan-qr">
<img src="https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/07/1499401426qr_icon.svg">
<a/>
<canvas hidden="" id="qr-canvas"></canvas>
<div id="qr-result" hidden="">
<b>Data:</b> <span id="outputData"></span>
</div>
</div>
<script src="./src/qrCodeScanner.js"></script>
</body>
</html>
(Javascript)
const qrcode = window.qrcode;
const video = document.createElement("video");
const canvasElement = document.getElementById("qr-canvas");
const canvas = canvasElement.getContext("2d");
const qrResult = document.getElementById("qr-result");
const outputData = document.getElementById("outputData");
const btnScanQR = document.getElementById("btn-scan-qr");
let scanning = false;
qrcode.callback = res => {
if (res) {
outputData.innerText = res;
scanning = false;
video.srcObject.getTracks().forEach(track => {
track.stop();
});
qrResult.hidden = false;
canvasElement.hidden = true;
btnScanQR.hidden = false;
}
};
btnScanQR.onclick = () => {
navigator.mediaDevices
.getUserMedia({ video: { facingMode: "environment" } })
.then(function(stream) {
scanning = true;
qrResult.hidden = true;
btnScanQR.hidden = true;
canvasElement.hidden = false;
video.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreen
video.srcObject = stream;
video.play();
tick();
scan();
});
};
function tick() {
canvasElement.height = video.videoHeight;
canvasElement.width = video.videoWidth;
canvas.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);
scanning && requestAnimationFrame(tick);
}
function scan() {
try {
qrcode.decode();
} catch (e) {
setTimeout(scan, 300);
}
}
Problem
The problem is that you are probably using a live server or just opening the html file, but in the sandbox parcel-bundler is used. var qrcode from the library collides with your const qrcode.
Solutions
Type module
Replace
<script src="./src/qrCodeScanner.js"></script>
with
<script type="module" src="./src/qrCodeScanner.js"></script>
Rename
Change your variable to something else like const myQrcode
Use a bundler
You can use parcel-bundler as in the sandbox or any other that will resolve variable collision for you

How can I upload a file to a github repo in Javascript?

I have an audio file which is generated by a JS script integrated to my streamlit web-app with components.html, like this:
components.html(
"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- Set up your HTML here -->
<center>
<p><button id="record">Record</button></p>
<div id="sound-clip"></div>
</center>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script>
// Set up the AudioContext.
const audioCtx = new AudioContext();
// Top-level variable keeps track of whether we are recording or not.
let recording = false;
// Ask user for access to the microphone.
if (navigator.mediaDevices) {
navigator.mediaDevices.getUserMedia({ "audio": true }).then((stream) => {
// Instantiate the media recorder.
const mediaRecorder = new MediaRecorder(stream);
// Create a buffer to store the incoming data.
let chunks = [];
mediaRecorder.ondataavailable = (event) => {
chunks.push(event.data);
}
// When you stop the recorder, create a empty audio clip.
mediaRecorder.onstop = (event) => {
const audio = new Audio();
audio.setAttribute("controls", "");
$("#sound-clip").append(audio);
$("#sound-clip").append("<br />");
// Combine the audio chunks into a blob, then point the empty audio clip to that blob.
const blob = new Blob(chunks, { "type": "audio/wav; codecs=0" });
audio.src = window.URL.createObjectURL(blob);
// Clear the `chunks` buffer so that you can record again.
chunks = [];
};
mediaRecorder.start();
recording = true;
$("#record").html("Stop");
// Set up event handler for the "Record" button.
$("#record").on("click", () => {
if (recording) {
mediaRecorder.stop();
recording = false;
$("#record").html("Record");
} else {
$("#record").html("Stop");
}
});
}).catch((err) => {
// Throw alert when the browser is unable to access the microphone.
alert("Oh no! Your browser cannot access your computer's microphone.");
});
} else {
// Throw alert when the browser cannot access any media devices.
alert("Oh no! Your browser cannot access your computer's microphone. Please update your browser.");
}
</script>
</body>
</html>
"""
)
Since I'm using Streamlit I need to upload the generated file to a bucket (I was thinking to use a simple github repo for now), but I have problems understanding how to do it given the fact that the script is wrapped inside components.html. Is it possible to upload the file and later retrive it to use it inside my python script for some calculations?

Continuously play overlapping audio loop

I want to continuously play audio in a loop, but each repetition is supposed to overlap with the previous one. Another button should be able to stop the loop.
This is what I tried:
var audio = new Audio(... Create audio
audio.ontimeupdate = ... Use ontimeupdate event to check if audio almost over
if (event.target.duration - event.target.currentTime <= 1 && audio == event.target) ... Check if overlap is 1 second and make sure the event is triggered by the current audio (because audio will be overwritten, this is only supposed to trigger once per repetition)
audio = new Audio(); Discard the reference to the "old" (currently still playing the last second) audio and create a "new" audio instead, copying all relevant properties src and ontimeupdate
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Audio loop</title>
</head>
<body>
<button id="start">Start</button>
<button id="stop">Stop</button>
<script>
var audio = new Audio("data:audio/mpeg;base64,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");
audio.ontimeupdate = function(event) {
if (event.target.duration - event.target.currentTime <= 1 && audio == event.target) {
audio = new Audio();
audio.src = event.target.src;
audio.ontimeupdate = event.target.ontimeupdate;
audio.play();
}
};
document.getElementById("start").onclick = function() {
audio.play();
};
document.getElementById("stop").onclick = function() {
audio.pause();
};
</script>
</body>
</html>

p5js AudioIn function not working on instance mode

I was converting my p5js code to instance mode to run 2 canvases in the same DOM but my p5.AudioIn() function is not working. The error I get is referencing Failed to construct 'AudioWorkletNode'. I have uploaded a screenshot of the error below because it has more information about it. Why isn't AudioIn not working when converted to instance mode but works on global mode.
let s2 = function(sketch) {
sketch.quinnListenMic;
sketch.setup = function() {
let cnv = sketch.createCanvas(300, 300);
cnv.mousePressed(sketch.userStartAudio);
sketch.quinnListenMic = new p5.AudioIn(); //ERROR HERE
sketch.quinnListenMic.start();
}
sketch.draw = function() {
sketch.background(100)
sketch.micLevel = quinnListenMic.getLevel();
console.log(micLevel)
}
}
var myp5_2 = new p5(s2);
<html>
<head>
<script defer src=https://cdn.JsDelivr.net/npm/p5></script>
<script defer src=https://cdn.JsDelivr.net/npm/p5/lib/addons/p5.dom.min.js></script>
<script defer src=https://cdn.JsDelivr.net/npm/p5/lib/addons/p5.sound.min.js></script>
<script src="https://cdn.jsdelivr.net/npm/p5#1.4.0/lib/p5.js"></script>
</head>
<body>
</body>
</html>
There were a couple of issues, fixed below with comments:
let s2 = function(sketch) {
// sketch.quinnListenMic; doesn't make sense. 1) You don't want to store your variables on the p5 instance, and 2) that statement doesn't actually do anything
// This is how you declare a local variable for use in setup/draw functions:
let quinnListenMic;
sketch.setup = function() {
let cnv = sketch.createCanvas(300, 300);
cnv.mousePressed(sketch.userStartAudio);
quinnListenMic = new p5.AudioIn(); //ERROR HERE
quinnListenMic.start();
}
sketch.draw = function() {
// Fixed local variable declaration again
// Note: there is a bug with AudioIn.getLevel not working in all browsers
let micLevel = quinnListenMic.getLevel();
// Let's not spam the console log
// console.log(micLevel)
sketch.background(sketch.map(micLevel, 0, 1, 0, 255));
}
}
var myp5_2 = new p5(s2);
<html>
<head>
<!-- Your script tags were not valid -->
<script src="https://cdn.jsdelivr.net/npm/p5#1.4.0/lib/p5.js"></script>
<!-- For some reason p5.sound does not work with the defer attribute -->
<script src="https://cdn.jsdelivr.net/npm/p5#1.4.0/lib/addons/p5.sound.min.js"></script>
</head>
<body>
</body>
</html>

Using HtmlMediaElement.captureStream() to get the audio from a video

I'm trying to capture the audio track from a video and play it separately. I wrote the test page shown below. I'm able to capture the stream and I get a valid audio track with readyState == "live", but I hear nothing. What am I doing wrong?
The video I'm using comes from here: http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4. I'm serving the HTML and the video locally to avoid CORS issues.
<head>
<script>
function captureAudio() {
const videoEl = document.getElementById("video")
videoEl.volume = 0.0
const videoStream = videoEl.captureStream()
const audioTrack = videoStream.getAudioTracks()[0]
const audioStream = new MediaStream()
audioStream.addTrack(audioTrack)
const audioEl = document.createElement("audio")
audioEl.srcObject = audioStream
audioEl.autostart = true
audioEl.volume = 1.0
audioEl.muted = false
}
</script>
<body>
<video id="video" src="http://localhost:3000/BigBuckBunny.mp4" controls onplay="captureAudio()" />
</body>
</html>
It works if you set a volume different than 0 (for example, 0.5). I have modified your code and hosted it on Glitch. When you pause the audio (that I have attached to the DOM so you can interact with it), you can clearly hear the different sources of sound, one from the video and one from the audio.
<html>
<head>
<script>
function captureAudio() {
const videoEl = document.getElementById("video");
videoEl.volume = 0.5;
const videoStream = videoEl.captureStream();
const audioTrack = videoStream.getAudioTracks()[0];
const audioStream = new MediaStream();
audioStream.addTrack(audioTrack);
const audioEl = document.createElement("audio");
audioEl.controls = true;
document.body.append(audioEl);
audioEl.srcObject = audioStream;
audioEl.play();
audioEl.volume = 1.0;
audioEl.muted = false;
}
</script>
</head>
<body>
<video
id="video"
crossorigin
src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
controls
onplay="captureAudio()"
/>
</body>
</html>

Categories