Making WAVs: Understanding, Parsing, and Creating WAV Files in JavaScript
ฝัง
- เผยแพร่เมื่อ 21 ส.ค. 2024
- The WAVE file format is a binary format that encodes high fidelity audio data. But how is the audio encoded and stored? How can these files be read and created in JavaScript? That's what we'll find out in this video!
=[ 🔗 Links 🔗 ]=
💌 Updates to your inbox: tinyletter.com...
⭐️ Patreon: / lowleveljavascript
💻 Github Repo: github.com/Low...
github.com/fra...
github.com/fra...
soundfile.sapp....
en.wikipedia.o...
www.tactilemedi...
en.wikipedia.o...
en.wikipedia.o...
github.com/fra...
github.com/fra...
I have no idea about JS and was just looking for informations about the structure of wave files, after your video i feel very comfortable to handle those in python now, thank you!!
Glad it was helpful to you. I intentionally made this video so it was less about language specifics and more about formats.
I'm in the exact same situation.
What a ridiculously thorough but concise video. Exactly what I needed after being disappointed by the wiki page. Keep it up man!
I’m not specialist with computer or even coding , these all are new information for me , i think i took more additional formation
Thank you so much 🙏🏼
Very nice explanation, would like to see more videos of this kind. I created a few years ago a parser for WebSocket protocol in vanilla JS, arcsecond seems to ease the process of parsing a lot thanks for sharing it, it may be an idea for your future videos to analyze binary protocols and file formats.
Thanks. I am working in java on a project. I needed to know the structure of wave files and how to parse them. This helped even though you use JS. Good job being language agnostic!
Glad it was helpful - it was a conscious choice to keep the information about the format language agnostic, while keeping the js parts widely applicable as well.
This is amazing. It's fascinating to see how powerful JS really is (thanks to libraries ofc), when it is often perceived as a "language for developing websites". Keep going!!!
It is impressive, but keep in mind that it is still terribly inefficient
Thank you a lot mate. I'm a web dev and hadn't known about such low-level things. I want to make some beat detector on node and now I'm studying "sound" and how to do this detection. Previously I hadn't known anything about sound/bitrates/discretization/frequency etc. After watching your video I believe I should extract the sample data and just find the Extremum of every sample to find the most strong noise. So will be working in this way. Thank you again! You're the best JS dev I've ever known.
Thank you Sviat, that means a lot!
Congrats! I really enjoyed this video, finally someone that writes real code and does something that not many developers dare doing. Looking forward to see more videos like this one.
SOO NICE ,, I AM SEEING SO MANY VARIANTS IN YOUR VIDEO MAKING , NICELY DONE IT , FORMATING WELL
GREAT INFORMATION , NARRATING WITH DIFFERENT TYPES OF SLIDES
Excellent! Excellent! Excellent!
This helped me understand PCM format, very helpful, thanks!
Thank you man! Continue.
Really beautiful video! I'm really impressed by the quality and level of professionalism
Thanks Sphere!
Very very nice explanation, i just meet the channel and its one of the best i have ever seen. Congrats!.
What a Channel!!!!!!!! S2
Thank you soo much, that was one of the cleanest tutorials I've ever seen
Cheers!
very big fan of this! i cant wait to see what other kinds of parsers and stuff.
idea: write a wasm parser (maybe even a sort of assembler or smth)
o hi
@@Sidney600MC oh hey sidney
100/10 my rating for this video, so much useful dude
Thanks Varun - glad to hear it!
You can do this with regular ol' web JS too by using to upload a binary file, and then you can just open up the blob, convert to either a Uint8Array or a Uint32Array, and work from there.
Absolutely
That was incredible.
Great video! Very helpful in understanding wav files, and highlights some very cool libraries.
I'll make waveform like Sound cloud waveform in my app! Thank you for your video. I was really really helped for you.
So cool! Thanks!
Pretty profesional dedicated video, thank you so much!
So useful! Thank you for your video. I think this will go great with Fabfilter's bitrate video and such.
It's also just as I was interested in decoding audio formats. For example, to make a customizable audio spectrum in Rust (I've seen great sketches already in js). But decoding compressed audio files is complicated 7_7
And I can imagine how difficult it would be to decode video compressed files as well.
I like to think of it like: Things you don't know how to do are impossible, but once you find out how to do them, they just become hard. And in comparison to impossible, hard is easy!
@@LowByteProductions Hard is easier than impossible, right?
Can't thank you enough! ...
pure #CodeGasm... thx for the ride!
your videos are amazing! Thank you so much!
Thank you! Fantastic content
An annoying extension of the wave format has become common: waveformatextensible. It has a codec id of FFFE or -2 and a longer 'fmt ' chunk to encompass additional fields and the actual format as a long ass GUID, because in the Microsoft universe you will no doubt have quadrillions of formats. It can be treated in place as codec 1 (int) or 3 (float).
You can probably accept files with extra data at the end. It could be a metadata tag not included in the chunk structure or unknown data after extraction from a package without determining the length of the file.
great video!
Amazing video, thank you very much :)
Hehehe i can hear you in there, fellow Dutchman. Your subtle accent betrays you! Still very subtle though, so props on your good English
hahaha eigenlijk kom ik uit Engeland, maar ik heb zo lang in Nederland gewoond dat nu heb ik een klein beetje accent 😂
amazing thank you!
Thank you! Continue.
Even myself as a C++ dev has respect for this JavaScript channel. Do you know how to interpolate a 22050 8 bit Depth WAV to a 44100 16 Bit one?
Double up the samples and use linear interpolation to map values in 0x00 - 0xff to the 0x0000 - 0xffff range. Should correctly account for twos complement encoding as well.
Awesome video ☺️
great stuff mate
Very noice video, love it!
amazing!!! thank you!
I think I can answer the question at 11:46 about the BlockAlign being a non-integer. Basically, if the NumChannels is an integer (which it should be-- imagine having 3.5 channels??) and the BitsPerSample is a multiple of 8 (which should also be true-- e.g., 16-bit, 24-bit, 32-bit), it's not possible for "NumChannels * BitsPerSample/8" to return a non-integer.
Yeah, basically odd (num of channels here) * even (bitrate) = even always. Cool!
HTTPS connections & I/O next!
Please tell us about PNG format
Your file size checking error message should expect size + 8 bytes in comparison with file.length.
Good video. Btw new version of construct-js has a lot of breaking changes. Stick with the repo for testing.
my audio is very muddy and sharp tone because massive amount of vst plugins are used and I have suspicion there is some software issue with .wav file cant convert/calculate the data well, so how do I optomize windows for best .wav calculations.
nice! very helpfull video, i was wondering if you can explain how to make an NSF file from scratch just like how you covered here BUT i dont expect you to have to go through the emulator side of it since its an NES sound format, just like go through the basics of how the file is structured and creating a parser. I made an emulator in freebasic and the next step is sound so its alot of help if there was a video covering it :)
So great!
Do you know about Tsoding's video about making music with Haskell, which is about generating .wav files?
(well technically it's not really the .wav format...)
I have indeed seen the video, and I love Tsoding's content
incredibly useful chart in the beginning, I just paused the video and that was all I needed to process my uncompressed audio signal in C. Why does the endianness switch back and forth in between metadata fields?
The big endian fields are actually text data, but all fit into 32 bit ints. I suppose that's just a more exact way to specify them, without having to worry about confusion surrounding encodings etc
Hey, great vid Francis!
I wonder what's causing the output.result to be [ [ 'RIFF', 88236, 'WAVE' ], Object [Generator] {} ] at 12:58 of the video? It would be really helpful if you help me out :)
I suppose ArcSecond got some groundbreaking updates to it? If yes, please can you provide a workaround over this?
Hey Komi, thanks!
Arcsecond did indeed get an update - the API for coroutine changed a little bit. If you check the docs on the github page github.com/francisrstokes/arcsecond#coroutine, you should be able to see the changes that are required.
Hope that helps!
@@LowByteProductions thank you so much! Love your humble nature! I love learning from your channel because of the atmosphere in your videos is the most comfortable one I ever found on YT. Yours is the only channel on YT I follow for programming :)
Edit: Thanks, I tried it out and it works like a charm, I love you man!
Thanks for the excellent video. I am a new programmer and I am trying to create a small program that parses a wav file and does some processing with it, namely, reverse it, slow it down, make it louder and so on. Does anyone have any idea what specific parts of the file I need to manipulate and where to locate them??
would you recommend for a totally newbie to use JS for parsing different types of files or going to some low level languages like C ?
On that basis alone it's kind of hard to say.
The advantage of using something like C is pretty much always going to be speed. If the problem you're solving (and the problem is rarely the parsing itself, but rather whatever you end up doing with the structured representation!) needs to be done very fast (for example: realtime transcoding), then C would certainly have an edge there. But if it's not something particularly time bound (for example: You only open and parse the file once, and the majority of the program time is spent manipulating the structure), then the expressivity you gain with a higher level language is probably going to be worth more than the speed gains. It's pretty unlikely that a complete newbie is going to be facing these kinds of constraints, however. My personal view is that expressivity is generally worth more when learning, because you can focus on the problem itself rather than surrounding details.
The trickiest part about this question is that there is no right or wrong. It's even better if a newbie learns from both ends of the spectrum - spending some time in a high level language and some in a low level language. Tackling challenges on leetcode or hackerrank in 2 different languages will really highlight the strengths and weaknesses of the two approaches, and help develop intuition about when and where to make a particular choice.
Haha, i too created binary data reading module in node.js for myself.
Nice - is it open source? I'd love to take a look.
@@LowByteProductions it's on a dead laptop and i think i deleted it :D
@@LowByteProductions but there's c++ code for reading different types of data from memory that i put on github github.com/PogromistDev/Memory
*Cycle duration formula seems wrong* to me (can anybody clarify) : because Hz/Hz is not seconds
It should be number of cycles
Hi Swaminath,
I think the choice of the word "duration" was probably wrong here. What is really being calculated here is the number of samples there are in a single cycle relative to the sample rate. Hope that helps clarify things!
Go listen to Wav Files by Lupe Fiasco, I'm here because of its lyrical breakdown. Plus I'm a low level web scrapper.
ParseError 'endOfInput' (position 12): Expected end of input but got '0x66' Anyone get this error ?
so how do i boost wav audio using php or js or html? i need to get past 100% volume, anyone help please??
Hey I was wondering, do you have discord? Because having a community there would be awesome
No I haven't made a discord for the channel (yet). The closest thing to a community there is right now is the subreddit, but it's not that lively!
@@LowByteProductions I see.
I guess the subreddit isn't very active because you don't have that much subscribers and views right now. So it will slowly grow along with your audience :)
Are you interested then? Because I can set one up and invite you there.
Thanks for the offer! But I think i will set one up myself soon 👍
@@LowByteProductions Great! Invite us all there once you do :)
@@LowByteProductions Please invite me to it when you do :)
this is how you make sound lol
What does low level mean?
Thank you so much for this! I just uploaded a video that's about creating 'a sound from itself', like a fractal, and your awesome code made it possible. Check it out when you have the chance :) Much love and keep rockin'!!!
What's that background?
1:42 The subtle shade...
yeah good video but as a noob idk how to install arcsecond / can't find anything to eyplain me how to do it... Can someone help ?
Anyway thx for the information in the video, helped a lot :)
Arcsecond is a library you can install via npm, with `npm i arcsecond`.
If you don't know what that means, then you should google/TH-cam for "node npm tutorial" to see how to get node and npm set up on your system. Hope that helps!
@@LowByteProductions wow thank you soo much for that quick reply! Should work fine with ur description ;)) thank you so much for helping me :D
woow . i'm glad to be the frist comment
Whys certain bytes are big endian encoded and rest are little endian ? Whats the purpose for having this "mixed" endianess ?
It's been a while since I've last looked at the format, but if I remember correctly, the big ending values are really just strings. If you have a string of 4 (ascii) characters, you can represent that as a uint32. To make the encoding natural, the byte representing the first character is found at the most significant position, which makes it big endian.
Using libraries is so not low level. And actually makes your code unnecessarily confusing
Thanks for your comment Andrew. Arcsecond and construct-js are both libraries I wrote myself, from scratch, using zero dependencies. I've all but recreated their functionality on the channel across the various videos - in fact there is an entire series about building a parser combinator system.
If you're arguing that any use of libraries makes code confusing **in general**, then I'm going to have to disagree. IMO that is sort of teetering on absurd.
i have added an additional line on the code: riffChunkStruct.get('size').set(36 + soundData.length * 2);
just because i couldn't read the new .wav file. Is that line of code right?
I'm not at a computer to check, but if something like that line wasn't present then I would say it is probably wrongly missing indeed.
Hello, i have this fileStruct.toBuffer() is not a function when I try fs.writeFileSync(path.join(__dirname, './new.wav'), fileStruct.toBuffer());
I didnt see anything on github, thank's you if u can help me :)