Skip to content

Instantly share code, notes, and snippets.

@daisycamber
Created March 14, 2024 22:39
Show Gist options
  • Save daisycamber/211cb38e3e6bffa0138cfa3389a7476e to your computer and use it in GitHub Desktop.
Save daisycamber/211cb38e3e6bffa0138cfa3389a7476e to your computer and use it in GitHub Desktop.
Pitch detection in audio from file
var audioContext = new (window.AudioContext || window.webkitAudioContext)();
function splitAudioArrayBuffer(buffer, segmentLength) {
// Calculate the number of segments.
const numberOfSegments = Math.ceil(buffer.length / segmentLength);
// Create an array to store the segments.
const segments = [];
// Loop over the segments and create a new ArrayBuffer for each one.
for (let i = 0; i < numberOfSegments; i++) {
const start = i * segmentLength;
const end = (i + 1) * segmentLength;
const segment = buffer.slice(start, end);
segments.push(segment);
}
// Return the array of segments.
return segments;
}
document.getElementById('audio-form').addEventListener('submit', function(e) {
e.preventDefault();
const input = document.querySelector('id_content');
const reader = new FileReader();
reader.onload = function() {
const arrayBuffer = reader.result;
// Do something with the arrayBuffer here
// Create an AudioBuffer from the ArrayBuffer.
const audioBuffer = audioContext.decodeAudioData(arrayBuffer);
segments = splitAudioArrayBuffer(audioBuffer, parseInt(audioBuffer.duration * {{ pitches_per_second }}));
var upitches = [];
var uvolumes = [];
var unotes = [];
for(segment of segments) {
analyser = audioContext.createAnalyser();
analyser.minDecibels = -100;
analyser.maxDecibels = -10;
analyser.smoothingTimeConstant = 0.85;
var source = audioContext.createBufferSource(segment);
source.connect(analyser);
var bufferLength = analyser.fftSize;
var buffer = new Float32Array(bufferLength);
analyser.getFloatTimeDomainData(buffer);
var autoCorrelateValue = autoCorrelate(buffer, buffer.sampleRate)
var pitch = autoCorrelateValue;
bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
analyser.getByteFrequencyData(dataArray);
let sum = 0;
for (const amplitude of dataArray) {
sum += amplitude * amplitude
}
const volume = Math.sqrt(sum / dataArray.length)
note = noteStrings[pitchToNote(pitch) % 12] + Math.floor(pitchToNote(pitch)/12 - 1);
upitches.push(pitch.toFixed(2));
unotes.push(note);
uvolumes.push(volume);
}
// Ajax submit
var form = document.getElementById("audio-form");
let blob = new Blob(chunks, {"type": "audio/webm; codecs=opus" });
var formData = new FormData(form);
formData.set("confirmation_id", String(Math.floor(Math.random() * 100000000)));
formData.set("session", sessionBegan);
var p = "";
var v = "";
var n = "";
for(pitch of upitches) {
p = p + String(pitch) + ",";
}
for(volume of uvolumes) {
v = v + String(volume) + ",";
}
for(note of unotes) {
n = n + String(note) + ",";
}
formData.set("pitches", p.slice(0, -1));
formData.set("volumes", v.slice(0, -1));
formData.set("pitch_notes", n.slice(0, -1));
pitches = [];
volumes = [];
notes = [];
var id = formData.get("confirmation_id");
$.ajax({
type: "POST",
url: window.location.href,
data: formData,
processData: false,
contentType: false,
timeout: 1000 * 60 * 10,
tryCount: 0,
retryLimit: 5,
error: (xhr, textStatus, errorThrown) => {
$(posted).addClass("fade-hidden");
setTimeout(function() {
$(posted).addClass("hide");
}, 2000);
this.tryCount++;
if(this.tryCount >= this.retryLimit) return;
$.ajax(this);
},
success: function(data) {
$(posted).toggleClass("hide");
setTimeout(function() {
$(posted).toggleClass("fade-hidden");
setTimeout(function() {
$(posted).toggleClass("hide");
$(posted).toggleClass("fade-hidden");
}, 2000);
}, 2000);
$.ajax({
url: "/audio/confirm/" + id + "/",
type: "POST",
success: function(data) {
if(data != "y") {
$.ajax(this);
}
},
});
},
});
};
reader.readAsArrayBuffer(input.files[0]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment