How to upload audio file with fetch into audio context? - javascript

I am trying to upload an mp3 from my computer into a soundtouch audio context in order to change the tempo and pitch.
HTML
<form class="form" id="form">
<input type="file" id="inputFile"><br>
<button type="submit">Upload File</button>
</form>
JavaScript:
const myForm = document.getElementById("form");
const inputFile = document.getElementById("inputFile");
myForm.addEventListener("submit", e => {
e.preventDefault();
const data = new FormData();
data.append("inputFile", inputFile.files[0]);
playBtn.setAttribute('disabled', 'disabled');
if (shifter) {
shifter.off();
}
fetch(data)
.then((response) => response.arrayBuffer())
.then((buffer) => {
audioCtx.decodeAudioData(buffer, (audioBuffer) => {
shifter = new PitchShifter(audioCtx, audioBuffer, 16384);
shifter.tempo = speedSlider.value;
shifter.pitch = pitchSlider.value;
shifter.on('play', (detail) => {
currTime.innerHTML = detail.formattedTimePlayed;
progressMeter.value = detail.percentagePlayed;
});
duration.innerHTML = shifter.formattedDuration;
playBtn.removeAttribute('disabled');
});
});
})
When I try this code, I get two error messages:
GET ...(port number)... 404 (NOT FOUND)
100.64.5.65/:1 Uncaught (in promise) DOMException: Unable to decode audio data
Any help would be appreciated as I don't know how to fix this.
code screenshot

Related

Convert an image to base64 in javascript

I want to transform my image into base64 and then into JSON to send it via a post request to a server in java script.
I have looked for several solutions on the internet but none of them really work. Can someone explain to me the logic to have to achieve the code?
For now, I have this code:
JS code :
<script>
function convert (){
//image = btoa(URL="../static/images/images_final.jpg");
fetch("/predict" ,{
method: "POST",
body: JSON.stringify({result})
})
}
var file = window.document.querySelector('#form-base64-converter-encode-image-file').files[0];
getBase64(file);
const fileInput = document.getElementById("fileInput");
fileInput.addEventListener("change", e => {
const file = fileInput.files[0];
const reader = new FileReader();
reader.addEventListener("load", () => {
console.log(reader.result);
});
reader.readAsDataURL(file);
});
</script>
htlm code :
<form>
<input type="file" id="fileInput">
<button class="button"
type="reset"
onClick="convert()">
<h4>ENVOYER </h4>
</button>
</form>
API flask:
#app.post("/predict")
def predict_image():
req = request.get_json(force=True)
b64Image = req["image"]
buf = base64.b64decode(b64Image)
return print(b64Image[:20], buf[:20])

Choosing audio format when saving data locally on a web app

I have a web app getting some audio recording input from the user.
And there is a button to save it locally as an audio file.
The resulting file I am getting is of ogg-opus format. Concretely when I use the file command I get this in the terminal:
MyMac$ file Clip.wav
Clip.wav: Ogg data, Opus audio,
MyMac$
I can check that the recording is all right using VLC.
On the other hand I can't play the file with afplay as is normally possible with an mp3, m4a or wav file.
MyMac$ afplay Clip.wav
Error: AudioFileOpen failed ('typ?')
MyMac$
Here follows my relevant code:
if (navigator.mediaDevices.getUserMedia) {
// getUserMedia is supported.
const constraints = { audio: true };
let chunks = [];
let onSuccess = function(stream) {
const mediaRecorder = new MediaRecorder(stream);
visualize(stream);
........
mediaRecorder.onstop = function(e) {
........
audio.setAttribute('controls', '');
........
audio.controls = true;
const blob = new Blob(chunks, { 'type' : 'audio/wav;codecs=0' });
chunks = [];
........
upload.addEventListener("click",
function(event) {loadToServer(blob)})
........
}
mediaRecorder.ondataavailable = function(e) {
chunks.push(e.data);
}
}
let onError = function(err) {
console.log('The following error occured: ' + err);
}
navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError);
} else {
console.log('getUserMedia not supported on your browser!');
}
I would like to know how to change my code in order to generate a proper wav file or even mp3.
Note:
I have made trials modifying this line of code:
const blob = new Blob(chunks, { 'type' : 'audio/wav;codecs=0' });
in various ways, but is has no effect at all.
In order to specify the mimeType of your recording you need to tell the MediaRecorder which mimeType you prefer before it starts the recording.
- const mediaRecorder = new MediaRecorder(stream);
+ const mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/wav' });
Unfortunately audio/wav is not supported by any browser. You will get an error when trying the snippet above.
Since I needed wav recordings as well I built a library which is meant to add this functionality. It's called extendable-media-recorder because it could be extended with any other (audio) codec you like.
If you don't want to use a third party library and keep the browser using the codec it likes best you can save your file like this in order to get a valid file with the correct suffix.
- const blob = new Blob(chunks, { 'type' : 'audio/wav;codecs=0' });
+ const blob = new Blob(chunks, { 'type' : mediaRecorder.mimeType });
The suffix would then be the portion of the type after the slash and before a possible semicolon.
Here is an example of a full HTML document that uses jspm to load extendable-media-recorder without a bundler.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
</head>
<body>
<button id="start" disabled>start</button>
<button id="stop" disabled>stop</button>
<script type="module">
import { MediaRecorder, register } from 'https://jspm.dev/extendable-media-recorder';
import { connect } from 'https://jspm.dev/extendable-media-recorder-wav-encoder';
const $start = document.getElementById('start');
const $stop = document.getElementById('stop');
await register(await connect());
const chunks = [];
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const mediaRecoder = new MediaRecorder(stream, { mimeType: 'audio/wav' });
mediaRecoder.addEventListener('dataavailable', ({ data }) => {
chunks.push(data);
});
mediaRecoder.addEventListener('stop', ({ data }) => {
const blob = new Blob(chunks, { type : mediaRecoder.mimeType });
console.log(blob);
});
$start.addEventListener('click', () => {
mediaRecoder.start();
$stop.addEventListener('click', () => {
$stop.disabled = true;
mediaRecoder.stop();
});
$start.disabled = true;
$stop.disabled = false;
});
$start.disabled = false;
</script>
</body>
</html>

how should I go by making a audio file converter in react

I am trying to make an audio file converter that lets a user submit a file. Then uses JavaScripts Web Audio API to convert the pitch and stretch the file. I have gotten as far as uploading the file, use file reader to onload a function that stretches and converts the pitch. Now I am trying to export that file with the changes and I can right now only download the original file but not with the changes. I dont know how to assign file = buffer because it's from another class. How should I got by making this happen?
convertFile () {
var fileInput = document.getElementById('audio-file')
var ctx = new AudioContext()
var convertFiles = document.getElementById('convert_button')
//load audio file listener
convertFiles.addEventListener("click", function() {
if (fileInput.files[0] == undefined) {
console.log("no file found")
return false
}
var reader1 = new FileReader()
reader1.onload = function(ev) {
ctx.decodeAudioData(ev.target.result). then(function(buffer){
var soundSource = ctx.createBufferSource()
soundSource.buffer = buffer
// create the stretch
soundSource.playbackRate.linearRampToValueAtTime(0.0185, ctx.currentTime)
//connect source
soundSource.connect(ctx.destination)
// convert pitch
var pitchChange = ctx.createBiquadFilter()
pitchChange.type = 'highpass'
pitchChange.frequency.value = 432
pitchChange.connect(ctx.destination)
})
}
reader1.readAsArrayBuffer(fileInput.files[0])
})
let file = fileInput.files[0]
let url = URL.createObjectURL(file)
let link = document.createElement('a')
link.href = url
link.download = file.name
link.click()
link = null
URL.revokeObjectURL(url)
}
render() {
return (
<div className="sec2">
<input type="file" id="audio-file" accept="audio/mpeg, audio/ogg, audio/*" name="file" onChange={this.uploadFile} />
<button type="button" id="convert_button" onClick={this.convertFile}>Convert to 432Hz</button>
<download onClick={this.downloadFile}>Download File</download>
</div>
)
}
}
export default ConverterSec2
I started looking into this... I fixed a couple issues such as the audio file being loaded twice. However this is work in progress answer... I haven't figure out the saving part yet.
class ConverterSec2 extends React.Component {
uploadFile = ({ target: { files } }) => {
console.log(files[0])
let data = new FormData()
data.append('file', files[0])
}
convertFile () {
var fileInput = document.getElementById('audio-file')
var ctx = new AudioContext()
var convertFiles = document.getElementById('convert_button')
//load audio file listener
if (fileInput.files[0] == undefined) {
console.log("no file found")
return false
}
var soundSource = ctx.createBufferSource();
var reader1 = new FileReader()
reader1.onload = function(ev) {
ctx.decodeAudioData(ev.target.result).then(function(buffer){
soundSource.buffer = buffer
// create the stretch
soundSource.playbackRate.linearRampToValueAtTime(0.0185, ctx.currentTime)
//connect source
soundSource.connect(ctx.destination)
// convert pitch
var pitchChange = ctx.createBiquadFilter()
pitchChange.type = 'highpass'
pitchChange.frequency.value = 432
pitchChange.connect(ctx.destination)
})
}
reader1.readAsArrayBuffer(fileInput.files[0]);
}
downloadFile() {
let fileInput = document.getElementById('audio-file')
let file = fileInput.files[0]
let url = URL.createObjectURL(file)
let link = document.createElement('a')
link.href = url
link.download = file.name
link.click()
link = null
URL.revokeObjectURL(url)
}
render() {
return (
<div className="sec2">
<input type="file" id="audio-file" accept="audio/mpeg, audio/ogg, audio/*" name="file" onChange={this.uploadFile} />
<button type="button" id="convert_button" onClick={this.convertFile}>Convert to 432Hz</button>
<button onClick={this.downloadFile}>Download File</button>
</div>
)
}
}
Live Demo

Getting image from a input field with Javascript to parse it to an API?

Currently trying to make use of an image upload class I created in php that saves an image to a folder and a text file but I want to save it from an api that I call in Javascript instead of by submitting a form.
Here I am trying to call the api
async function createTweet(e) {
const id = document.getElementById('user-id').getAttribute('data-user-id');
const tweet = e.target.parentNode.parentNode.querySelectorAll('input')[1]
.value;
const image = e.target.parentNode.parentNode.querySelectorAll('input')[0];
console.log(image);
const data = new FormData();
data.append('userId', id);
data.append('tweet', tweet);
data.append('tweet-image', image);
try {
const conn = await fetch('php/api/api-create-tweet.php', {
method: 'POST',
body: data,
});
const res = await conn.text();
getData();
// TODO show user he has created a tweet
} catch (error) {
console.log(error);
}
}
Just wondering what I can do with the image so I can read the file in my api with $_FILES['tweet-image'] and if I need to do anything to the form data to make it form type enctype
The code should work with some changes. You have two ways of doing it (see FormData # developer.mozilla.org):
Let's say you have a simple form:
<!-- just an example -->
<form method="post" action="form.php" enctype="multipart/form-data">
<input type="text" name="tweet" />
<input type="file" name="image" />
<input type="submit" />
</form>
<script>
/* prevent sending the form */
var form = document.forms[0];
form.onsubmit = function(e) {
e.preventDefault();
sendForm();
}
</script>
A. importing the <form> directly into FormData():
<script>
async function sendForm() {
// import form input here ->
const data = new FormData(form);
const conn = await fetch('form.php', {
method: 'POST',
body: data
});
const res = await conn.text();
}
</script>
B. make sure you actually append the .files[0] from the input[type="file"] into the formData():
<script>
async function sendForm() {
const data = new FormData();
const tweet = form["tweet"].value;
// notice the use of .files[0] -->
const image = form["image"].files[0];
data.append("tweet", tweet);
data.append("image", image);
const conn = await fetch('form.php', {
method: 'POST',
body: data
});
const res = await conn.text();
}
</script>
Then in your PHP file you should be able to access both $_POST["tweet"] (text) and $_FILES["image"] (file) in this example.

How to store base64 data in sql server

I have created a voice recorder in HTML.
first, it will request stream, after allowing request stream it will show two buttons, like "start" and "Stop". After recording it will convert blob URL to base64 data.
Now what I want is, I have a table SQLserver I want to store base64 data in that table. I am creating this web page using ASP .NET MVC. The base64 data is in javascript. I don't know how to connect to the server.
Please help me.
Thanks.
Html Page code:
<body>
<h1> Audio Recorder</h1>
<p> For now it is supported only in Firefox(v25+) and Chrome(v47+)</p>
<div id='gUMArea'>
<div>
Record:
</div>
<button class="btn btn-default mediaAudio" id='gUMbtn'>Request Stream</button>
</div>
<div id='btns'>
<button class="btn btn-default" id='start'>Start</button>
<button class="btn btn-default" id='stop'>Stop</button>
</div>
<div>
<ul class="list-unstyled" id='ul'></ul>
</div>
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="~/script.js"></script>
</body>
JavaScript Code:
'use strict'
let log = console.log.bind(console),
id = val => document.getElementById(val),
ul = id('ul'),
gUMbtn = id('gUMbtn'),
start = id('start'),
stop = id('stop'),
stream,
recorder,
counter=1,
chunks,
media;
gUMbtn.onclick = e => {
let mv = id('.mediaAudio'),
mediaOptions = {
audio: {
tag: 'audio',
type: 'audio/mpeg',
ext: '.mp3',
gUM: {audio: true}
}
};
media = mediaOptions.audio;
navigator.mediaDevices.getUserMedia(media.gUM).then(_stream => {
stream = _stream;
id('btns').style.display = 'inherit';
start.removeAttribute('disabled');
recorder = new MediaRecorder(stream);
recorder.ondataavailable = e => {
chunks.push(e.data);
if (recorder.state == 'inactive') saveLink()
};
log('got media successfully');
}).catch(log);
}
start.onclick = e => {
start.disabled = true;
stop.removeAttribute('disabled');
chunks=[];
recorder.start();
}
stop.onclick = e => {
stop.disabled = true;
recorder.stop();
start.removeAttribute('disabled');
}
function saveLink() {
let blob = new Blob(chunks, { type: media.type })
;
var reader = new window.FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function () {
var base64data = reader.result;
console.log(base64data.substr(base64data.indexOf(',') + 1));
alert(base64data.substr(base64data.indexOf(',') + 1));
}
}
Now it have base64 data in base64data variable, I want to store this variable sql server.
Regards.
Your solution has 2 parts:
Getting a blob out of the blob url
Sending that blob to the server
For first part you can use "Fake ajax" technique just pass blob url (url of download.ogg) as the url of your ajax
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200){
var result = this.response
}
}
xhr.open('GET', 'blob:http://example.com/bbdaabf8-ddf2-40d3-975d-ade742417c71');
xhr.responseType = 'blob';
xhr.send();
After ajax completes result will hold a blob now you just send it to ther server using this answer

Categories

Resources