Last active
April 27, 2022 18:52
-
-
Save literallylara/7ece1983fab47365108c47119afb51c7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* RIFF WAVE PCM file generator | |
* Reference: www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html | |
* | |
* @author Lara Sophie Schütt (@literallylara) | |
* @license CC0 | |
*/ | |
const DUR = 5 // duration in seconds | |
const NCH = 1 // number of channels | |
const SPS = 44100 // samples per second | |
const BPS = 1 // bytes per sample | |
const SIZE = DUR * NCH * SPS * BPS | |
// PCM Data | |
// -------------------------------------------- | |
// Field | Bytes | Content | |
// -------------------------------------------- | |
// ckID | 4 | "fmt " | |
// cksize | 4 | 0x0000010 (16) | |
// wFormatTag | 2 | 0x0001 (PCM) | |
// nChannels | 2 | NCH | |
// nSamplesPerSec | 4 | SPS | |
// nAvgBytesPerSec | 4 | NCH * BPS * SPS | |
// nBlockAlign | 2 | NCH * BPS * NCH | |
// wBitsPerSample | 2 | BPS * 8 | |
// data_size = DUR * NCH * SPS * BPS | |
// file_size = 44 (Header) + data_size | |
function dec2hex(n, l) | |
{ | |
n = n.toString(16) | |
return new Array(l*2-n.length+1).join("0") + n | |
} | |
function hex2str(hex) | |
{ | |
let str = [] | |
if (hex.length % 2) | |
{ | |
throw new Error("hex2str(\"" + hex + "\"): invalid input (# of digits must be divisible by 2)") | |
} | |
for (let i = 0; i < hex.length; i+=2) | |
{ | |
str.push(String.fromCharCode(parseInt(hex.substr(i,2),16))) | |
} | |
return str.reverse().join("") | |
} | |
function put(n, l) | |
{ | |
return hex2str(dec2hex(n,l)) | |
} | |
let data = "RIFF" + put(44 + SIZE, 4) + "WAVEfmt " + put(16, 4) | |
data += put(1 , 2) // wFormatTag (pcm) | |
data += put(NCH , 2) // nChannels | |
data += put(SPS , 4) // nSamplesPerSec | |
data += put(NCH * BPS * SPS, 4) // nAvgBytesPerSec | |
data += put(NCH * BPS , 2) // nBlockAlign | |
data += put(BPS * 8 , 2) // wBitsPerSample | |
data += "data" + put(SIZE, 4) | |
for (let i = 0; i < DUR; i++) | |
{ | |
for (let j = 0; j < SPS; j++) | |
{ | |
data += put(Math.floor((Math.sin(j/SPS * Math.PI * 2 * 440) + 1) / 2 * Math.pow(2, BPS * 8)), BPS) | |
} | |
} | |
const WAV = new Audio("data:Audio/WAV;base64," + btoa(data)) | |
WAV.setAttribute("controls","controls"); | |
WAV.play(); | |
document.body.appendChild(WAV) | |
/* Minified version with pre-defined header | |
// RIFF WAVE PCM | Mono | 44100Hz | 8 bit | |
for(i=44100*DUR,d="";i--;)d+=String.fromCharCode(~~((Math.sin(i/44100*6.283*440)+1)*128)) | |
new Audio("data:Audio/WAV;base64,"+btoa("RIFFdataWAVEfmt "+atob("EAAAAAEAAQBErAAARKwAAAEACABkYXRh/////w==")+d)).play() | |
// Web Audio API equivalent (assumes 44100 kHz sample rate) | |
a=new AudioContext() | |
s=a.createScriptProcessor(t=b=4096,1,1) | |
s.connect(a.destination) | |
s.onaudioprocess=function(e){for(i=0;i<b;)e.outputBuffer.getChannelData(0)[i++]=Math.sin(t++/44100*6.283*440)} | |
*/ |
how do you combine multiple audio files into a single wav file?
@aahedi You can read each file and merge the channels.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Line 65 returns 256 if I put an odd number as a frequency, which ends up translating to x100 (xFF +1). Probably beacuse if sin retruns 1, it's multuplied by 256 instead of 255.
I replaced:
data += put(Math.floor((Math.sin(j/SPS * Math.PI * 2 * 440) + 1) / 2 * Math.pow(2, BPS * 8)), BPS);
with
data += put(Math.round((Math.sin(j/SPS * Math.PI * 2 * 440) + 1) / 2 * (Math.pow(2, BPS * 8)-1) ), BPS);