Note: There is a download link in the video description, for all the code shown in the video. The linked page also includes a slightly improved version of the transforms that performs faster*, as well as code for inverse transforms. Also, if you want to understand what my transform codes do, the first step you should do is eliminate all for-loops for "num" and just assume that istep=ostep=1 and istep2=ostep2=n=0 and num=1, inlining these values into all equations and “if”s affected. This will make the code a lot simpler, as it will show what the single transform does. (Currently each transformation function can do several transforms in sequence/parallel). *) Benchmarks : In-place transformations per second, ignoring initialization time, with audio processing&windowing&rendering disabled, using constant predefined data: 96000-length (factors: 2 2 2 2 2 2 2 2 3 5 5 5): 0.01 - Naïve DFT only 30 - The code featured in the video 978 - The slightly improved code 2457 - libFFTW3 using FFTW_ESTIMATE 2865 - libFFTW3 using FFTW_MEASURE 3460 - libFFTW3 using FFTW_PATIENT (plan creation took 2 minutes) 3448 - libFFTW3 using FFTW_EXHAUSTIVE (plan creation took 16½ minutes) 96023-length (factors: 131 733): 0.01 - Naïve DFT only 5.2 - The code featured in the video 188 - The slightly improved code 276 - libFFTW3 using FFTW_ESTIMATE 381 - libFFTW3 using FFTW_MEASURE 383 - libFFTW3 using FFTW_PATIENT (plan creation took 3 seconds) 388 - libFFTW3 using FFTW_EXHAUSTIVE (plan creation took 14 seconds) 96043-length (factors: 96043; factors of 96042: 2 3 16007): 0.01 - Naïve DFT only 4.3 - The code featured in the video 68 - The slightly improved code 440 - libFFTW3 using FFTW_ESTIMATE 537 - libFFTW3 using FFTW_MEASURE 583 - libFFTW3 using FFTW_PATIENT (plan creation took ~3 minutes) 770 - libFFTW3 using FFTW_EXHAUSTIVE (plan creation took ~26 minutes) Oh by the way! I published this video a day in advance to the Patreon contributors on my Discord server.
@blacklion798 күн бұрын
@@Bisqwit It is very hard to beat libFFTW3, but I'm surprised by such difference, as your code looks very good and templates allow for additional optimizations at compile time
@emperorpalpatine60808 күн бұрын
Hey bisqwit , I missed your C++ videos. I remember many years ago I used to look at your code in awe , not understanding a thing. Today , I'm making a whole wave optic path tracing rendering engine parallelized on cuda + optix and C++... It's currently 40k LOC and growing. I'm happy to say I still don't understand shit about your code.
@tenaibms8 күн бұрын
At last! Though that is not to say you are not allowed to take your time with your videos, but I am quite glad to see one uploaded again.
@Bisqwit8 күн бұрын
Yeah, I really wanted to make one video before the end of 2024… Well, I started in the middle of December but I was not quite able to finish it before the end of 2024. Wasn’t far off, though. And I wanted to make one in my classical style: more code, less narration.
@nrdesign19918 күн бұрын
The nice thing about the DFT is that you don't have to do _all_ the bins for _all_ the frequencies. You can program it to look just for specific frequencies, e.g. for frequency shift keying decoders or other simple frequency detection jobs. And going for complex numbers is only partially needed as you can precalculate only the required values - handy for embedding this algorithm in simple but reliable microcontrollers.
@Bisqwit8 күн бұрын
Very true!
@pavelperina76298 күн бұрын
I'm kind of curious about more information. Yes, for one of a few frequencies, you can basically use correlation with sine and cosine functions or complex e^iwt and you can precalculate them into tables. But I don't know if you can use DFT for let's say only for 2-3kHz band, significantly lower the resolution of output (like here 48kHz to maybe 1920 vertical lines) or do some other tricks - I guess so.
@nrdesign19918 күн бұрын
@@pavelperina7629 The trick is to simply not calculate all bins. If you look at the formula for all frequencies, you can eliminate the outer sum and just calculate the n's and k's you're interested in. The input sampling rate determines the size of each bin. I don't remember how to calculate it off the top of my head but the information is out there. The complex numbers can indeed be approximated by sin/cos, but that always ends up in constant values, so you calculate them once and re-use them instead.
@bas777ien8 күн бұрын
He dropped the best programming example and thought we wouldn't notice
@yankilo8 күн бұрын
It's a pleasure to hear from you again, Joel. Happy New Year!
@georgeallen74877 күн бұрын
This is the type of project that is a Bisqwit classic. C++, SDL, and some very technical subject.
@literallynull8 күн бұрын
As a radio engineering undergrad, this is simply brilliant!
@shurgars8 күн бұрын
Lovely. A programming video from Bisqwit!! You meant a lot to me pursuing coputer science professionally about 7 years ago.
@thsstphok79378 күн бұрын
Plot twist: Bisqwit had to slow down his recording to .25x so people could follow his code. I miss so much his streams and seeing the coding light up fast!
@poohandim8 күн бұрын
I’ve always like your videos. Never give up!
@vaibhavmishra51798 күн бұрын
Happy New Year Bisqwit!
@TheRallyFTW8 күн бұрын
Bisqwit MIGHT be one of the coders of all time
@Bisqwit8 күн бұрын
Considering all the comments posted on my videos so far, yours was one of them.
@plantwateringcitizen87878 күн бұрын
2025 Christmas present delivered very early!! Thank you, Bisqwit - happy new year!
@Bisqwit8 күн бұрын
I tried to get this published before the end of 2024, but the project ran a couple of days late… I’m just happy I got it done nonetheless.
@Asdayasman6 күн бұрын
5:35 WHY lmao. Good to see you back. Could I please, once again, ask for a conclusion to the compiler project? Love you.
@Bisqwit6 күн бұрын
Are you refering to the text editing style there? That’s the automated tool doing its thing, trying to optimize for input speed… I admit it looks jarring… I will try to get back to the compiler project one of these months (or years), but right now at least until May, I definitely don’t have time for that undertaking. I mean, the code is already done, but the presentation is where I have the problem…
@Asdayasman6 күн бұрын
@@Bisqwit I am indeed referring to the text editing style. I thought you might have done it on purpose specifically to meme. I'm jazzed for the conclusion of the compiler project. I don't know how many times I've rewatched the existing parts, but it's not a healthy number.
@Humble_Electronic_Musician8 күн бұрын
Yay, a new Bisqwit video! God bless you!
@verysoftwares8 күн бұрын
Moikka Bisqwit! Tässä Leonard Somero sun Discordista, mulla menee hyvin ja projektit etenee. Kiva nähdä asiantuntemustasi tässä videossa. Eipä mulla muuta, rauhaisaa vuotta 2025 🙏
@Rand00817 күн бұрын
Welcome back. I remember I needed an FFT explanation, but now I don't remember for which project.
@vycdev8 күн бұрын
Happy New Year!!
@BlizzetaNet8 күн бұрын
BISQWIIIIIT! ❤❤❤❤❤ I cant tell you how much I love SDL, and this is another reason. Great video!
@placeholderhandlehere8 күн бұрын
It's a good day when Bisqwit uploads
@Mro197658 күн бұрын
Thank you cooley and tukey for your algorithm.
@Capewearer7 күн бұрын
Legend is back!
@axelkoster8 күн бұрын
Happy New Year
@tonym58578 күн бұрын
Happy new year with a video 👌💪
@harriehausenman86238 күн бұрын
"tool-assisted education video" 😄 love it
@movization8 күн бұрын
Happy New Year!
@fburton85 күн бұрын
A few years ago I had to calculate a power spectrum of a y vs time signal in ImageJ macro language. There wasn’t a readily available FFT function at that time, so I wrote a short (6 line?) function using sin and cos. I expected the DFT approach to be really slow, because it was when I last tried it back in the days of FORTRAN on a PDP-11 (before switching to FFT). Actually, it was plenty fast enough on modern hardware and so that’s the code I used for ‘production’.
@travelthetropics61908 күн бұрын
Happy new year! 😊
@wjdeh101108 күн бұрын
Happy New Year!!!
@bas777ien8 күн бұрын
Babe wake up, new programming masterpiece dropped
@alfaalfa998 күн бұрын
Long time no see you. Thanks for the video.
@jh0nny_350z8 күн бұрын
My god, you are so good!
@Bisqwit8 күн бұрын
I try to be… Thanks for writing!
@japedr7 күн бұрын
3:10 In audiodata.erase line, possible UB unless I'm mistaken: creating an iterator previous than begin() 13:00 wow I didn't know you could declare a one-use class like that. Awesome video, BTW!
@Bisqwit7 күн бұрын
3:10 There is no creation of an iterator previous than begin(). The formula end()-AudioRate always creates an iterator that is ≥ begin(), because the number of elements in the vector is never reduced below AudioRate (and it’s pre-initialized to this amount). Thank you!
@japedr5 күн бұрын
@@Bisqwit oh, I didn't realize that, thanks for the explanation!
@kadavr3146 күн бұрын
New Biswit video? HUMANITY RESTORED \[T]/
@vomaxHELLnO8 күн бұрын
I wish I had these superpowers
@0x90h8 күн бұрын
These superpowers are earned not given.
@youtubeenjoyer17438 күн бұрын
You lost me at a macro defining a struct with virtual methods inheriting another struct. That is some crazy++ right there.
@Bisqwit8 күн бұрын
In C++, class is the same as struct, with only a different default visibility setting. I often use struct instead of class when I want what I write next to be public by default rather than private.
@srccde8 күн бұрын
@@Bisqwit The different default visibility also applies to inheritance, though. struct A {}; class B : A {}; // private inheritance struct C : A {}; // public inheritance
@Bisqwit8 күн бұрын
Thanks! I didn’t actually know that part.
@MissNorington8 күн бұрын
@@Bisqwit But you did type "public:" in the struct, which was unnecessary. It is nice to have you back making programming videos again Bisqwit! Happy New Year!
@Bisqwit8 күн бұрын
Yes, the “public:” was technically unnecessary, but it served as a visual guide to separate the member variables from the list of methods - a standard visual pattern seen in C++ code. This visual pattern makes the struct contents faster to understand: Things above the “public:” are member variables, and things below the “public:” are public methods - while still keeping the member variables public (for unrestricted access without having to write getters and setters, that would clutter the presentation-oriented code).
@HarhaMedia8 күн бұрын
It was easy to follow until the DFT implementations. :-) Interesting use of preprocessor macros and I also like how the complexities are mostly hidden in the implementations while keeping the interfaces as simple as possible.
@ZomB19868 күн бұрын
3:17 There are many different Sigmoid functions (wiki lists 6 on a single page). Why did you choose the most computationally expensive? 14:45 There's a bit-fiddling approach to getting the 'highest 1 bit', which with slight input manipulation is faster than looping. 15:10 What wad is this music from Thanks for the video. This pretty much summarizes what I tried to learn from your thesis. If only it wasn't such guru-level C++ I could actually port it. (My native tongue is Java)
@Bisqwit8 күн бұрын
I chose the one that I discovered fastest, no other reason. The requirements were: • Input range is −∞ to +∞ • Output range is 0 to 1 • Inputs in range [−1, +1] will be translated to [0, 1] with little error And the tanh() function, with the adjustments indicated in the video, seemed to fit the bill.
@GrepGaming7 күн бұрын
What are your thoughts on someone like myself who wants to do some sort of meaningful project, but lacks the ideas/motivation on what to actually work on. I find myself struggling to come up with an idea that I want to stick with/is within the scope of possibility for a single person who has limited time? Thank you for another great video!
@Veso2668 күн бұрын
I waited so long to see a video like this again Thnx At first when I saw that editor I thought it would be made for DOS Wonder if somethibg like SDL exists in DOS
@Bisqwit8 күн бұрын
Allegro is pretty similar. The problem with DOS, though, is that there are no device drivers besides what the BIOS (dating from 1980s) provides. If you want to support different hardware, you have to implement your own drivers for all of them, separately. And then there’s the usage of 32-bit code, let alone 64-bit. You can use a DOS-extender (DPMI) to get the former, but for the latter, the task approaches the complexity of writing your own operating system.
@Veso2668 күн бұрын
@Bisqwit I see, u could write it only for Sound blaster so it would at least work in dosbox (not sure if Sound blasters or any other sound card at the time, ever supported 192khz sample rate) I do wonder, what advantages would 32bit or even 64bit code have in this case? Cant a 16bit cpu calculate numbers bigger then 65535 anyway it just does that in multiple steps
@Bisqwit8 күн бұрын
It’s not just the bitness, but the instruction set extensions, for example AVX2, which enable instructions that treat e.g. multiplying 8 floating point numbers in a single instruction. It also concerns with virtual memory addresses that are 64-bit. Although 32-bit would be sufficient to handle the needs of these programs (in most cases), on a 64-bit system size_t is 64 bits wide, which on a 16-bit system would four 16-bit registers… and the 16-bit platform has only like 5 16-bit registers available in the first place. That means that any operation treating two 64-bit values would require an extensive musical-chairs operation between memory and registers on the 16-bit DOS platform.
@Veso2668 күн бұрын
@@Bisqwit I see, so I guess the program would become very slow then since moving data from ram and back is slower then between registers I do wonder if this would be possible to demonstrate Could u compile this for 16bits without (significant) code change? I do wonder how fps would drop Although, I am not sure if linux can even run 16bit code (not sure if linux itself can even run on 16bit cpu)
@elultimopujilense8 күн бұрын
Awesome!
@steingamedev8 күн бұрын
What IDE do you use? It looks amazing! Edit: Never mind I found your video on it. I'll check it out.
@afmikasenpai8 күн бұрын
Neat implementation! 7:39 Is that rendered LaTeX at line 28?
@Bisqwit8 күн бұрын
Thanks! No, it’s not LaTeX. It is pure Unicode text: Xₙ = ∑ₖ₌₀ᴺ⁻¹ (xₖ · exp(-2iπnk/N)) I wrote the exp() like that because there was no superscript π in Unicode.
@afmikasenpai8 күн бұрын
@@Bisqwit Ahhh the N-1 threw me off a bit, it rendered so nicely. Thanks for the answer!
@Bisqwit8 күн бұрын
Actually that N-1 is the part I was not satisfied with, because it looks like N⁻¹… This was not the font I wanted to use for this part, but the font that I wanted was only available in the branch of that_terminal that does not have video recording…
@qaz1wsx2edc15 күн бұрын
Hello, i have watched a couple of your videos now and wonder about the os you are using. did you make it yourself?
@Bisqwit5 күн бұрын
I used Linux. But you only see fullscreened programs in this video.
@pavelperina76298 күн бұрын
Hi, this was somehow dense and lacking explanations. What I miss is benchmarking. Code uses STL at all cost maybe, I didn't even know that pi is defined in some numerical constants or that copy_n replaces memcpy, but this is personal preference I guess. I don't personally like it mostly because that templated code relying on inlining works painfully slow in debug mode with Microsoft compiler. One inefficiency seems to be allocating vectors instead of reusing them in FFT functions, although I don't know how many memory allocations are typically performed per second. Possible optimization could be something like not computing half of coefficients as there's a symmetry for real input signal, assuming only 2^N window size and for cleaner spectrum using something like hann window on input data, because DFT is periodic and there's always sudden change from end to to start adding noise to the spectrum - i guess subtracting linear function can work too, but not for 2d data i'm usually dealing with.
@Bisqwit8 күн бұрын
Yes, it was dense and lacking explanations for three reasons: ① I really wanted to get this video done before I have to return to fulltime focus on my work. ② Because I wanted to somewhat return to the roots of my channel (or at least do a homage to), where the code was in the focus and narration was rarely present if at all. ③ Because I am planning to eventually make an actual tutorial video on FFT (which I have already spent considerable time making animations for). Some benchmarks can be found in the pinned comment. For windowing I am using Gaussian rather than Hann (as per example found in Praat). For utilizing symmetries in the coefficients, I was kind of hoping the compiler would be smart enough to do that, but that doesn’t appear to be the case for the compilers I have tested. Their short ability to utilize SIMD in the functions where multiple transformations are performed in sequence was also a disappointment. I have previously tried both preallocating the buffers and also precalculating the coefficients (and also several other ideas); these ideas I used while writing my thesis, but here I aimed for a different compromise between simplicity and efficiency.
@anon_y_mousse5 күн бұрын
I'm curious as to why you use .cc and .hh for C++ file extensions instead of the more conventional .cpp and .hpp ?
@Bisqwit5 күн бұрын
"More conventional" is YMMV. The following are extensions broken down by different environments (from the "C++ Primer Plus" book): Unix uses: .C, .cc, .cxx, .c GNU C++ uses: .C, .cc, .cxx, .cpp, .c++ Clang uses: .C, .cc, .cxx, .cpp, .c++ and also .cppm for module interfaces Digital Mars uses: .cpp, .cxx Borland C++ uses: .cpp Watcom uses: .cpp Microsoft Visual C++ uses: .cpp, .cxx, .cc and also .ixx for module interfaces Metrowerks CodeWarrior uses: .cpp, .cp, .cc, .cxx, .c++
@anon_y_mousse5 күн бұрын
@@Bisqwit Right, so disregarding UNIX, .cpp is basically universal. The only people that still use UNIX are basically people that aren't going to be writing a lot of new software for the system, if any at all, and would more often use plain C anyhow.
@OrangeShellGaming4 күн бұрын
@@anon_y_mousse "basically universal" comes off as a bit disingenuous when many of the compilers mentioned that mainly or solely use .cpp are for legacy platforms like DOS (or Windows ;-), while *nix based systems like macOS and Linux are still very much in use. In practice neither .cc/.hh nor .cpp/.hpp is more 'conventional', it's a matter of preference - as long as you don't use .h for C++ headers.
@anon_y_mousse4 күн бұрын
@@OrangeShellGaming UNIX is not Linux. You can use GNU compilers on UNIX systems. Every platform, compiler and IDE he mentioned except for UNIX recognizes .cpp as a valid extension, and it's debatable whether UNIX really doesn't given that you can use GNU compilers on UNIX. While .cpp is more used than any other, it really shouldn't be an argument because I was asking him why he did something, not telling him he has to switch.
@OrangeShellGaming3 күн бұрын
@@anon_y_mousse LInux isn't Unix, because it isn't certified as such, but it basically is in all but name; the basic infrastructure is very much inherited/based on or at the very least inspired by Unix work; you have the same general directory structure, very similar basic command line tools, the basic syscalls are mostly the same, etc. Arguing that Linux isn't Unix is pedantry; arguing that Linux isn't very much like Unix is folly. (There are, or at least were until recently, actually some Linux distributions that are certified as Unix, so you could legitimately stake the claim that they at least are/were versions of Unix.) edit: posted another comment below this one - KZbin auto-deleted it, oh well.
@AlessioSangalli7 күн бұрын
Why would you sample at 96kHz? What kind of microphone do you use that has such a large bandwidth?
@Bisqwit7 күн бұрын
Hmm, my Blue Yeti Pro can in fact record at 192 kHz, 24-bit resolution.
@AlessioSangalli7 күн бұрын
@ that is just the supported frequency of the A/D converter, but a microphone is unlikely to be able to have an usable bandwidth of more than 15kHz that is not either noise or artifacts (PS I’m not an expert on mikes)
@Bisqwit7 күн бұрын
The Blue Yeti Pro has a frequency response range 20 Hz … 20 kHz, with signal-to-noise ratio 114 dB. However, (and we are obviously in the theoretical realm now) to accurately represent a 20 kHz digitized sinewave at any phase you need a much higher sampling rate than 40 kHz. At 40 kHz sampling rate, a 20 kHz sine wave under _ideal_ conditions (samples are always taken at peaks & valleys) cannot be told apart from a 20 kHz square wave or a 20 kHz triangle wave, and in the worst case the samples are always taken when the signal crosses the positive-negative boundary, resulting in a straight line (i.e. no signal at all). Even if you have 4x the number of samples compared to signal’s the wave length, you only get a vague representation of the signal that in the best case is not possible to tell apart from a triangle wave. You can try this yourself: use a spreadsheet program and fill a column with sine values such that the cycle is 4 lines long (this corresponds to e.g. 2000 Hz signal using 8000 Hz sampling rate, or 20 kHz signal using 80 kHz sampling rate). Plot these values and observe the shape. It’s pretty crude and definitely doesn’t look like a sinewave (and attempts to reconstruct the sine wave from it). Make sure to try different phase-shifts to the signal (you’ll note that attempts to reconstruct the original sinewave from the quantized form would result in wrong amplitude).
@AlessioSangalli6 күн бұрын
@@Bisqwit I am a little skeptical that a microphone, besides the marketing claims, can accurately record anything above 15kHz. Why would you want to include ultrasonic information when recording speech? Not to count that most speakers would just filter it out. What I mean is, you cannot really do that AD-DA conversion without the required band or low-pass filter (hence eliminating the square or triangle wave dilemma), and if none is provided the speakers will implement it when it's reproduced. In any case, the essence of my original comment was about why use such sampling frequency for speech, which has a pretty limited bandwidth, I believe by limiting the frequency range (and hence the noise) to few kHz one would have a more useful spectrogram. It's like when you hit "20MHz" on an oscilloscope when measuring slow signals, everything just improves (less noise) even if the scope supports 1Gsamples/s that's it
@Bisqwit5 күн бұрын
If a device has capability and capacity for quality, there’s no sense not using it, even if you can’t tell the difference. I don’t need to have perfectly trained hyper sensitive ear or super-HiFi playback hardware to know it. I have a long time ago made the mistake thinking that just because _I_ couldn’t tell the difference between 112 kbit/s MP3 and 320 kbit/s MP3, it doesn’t matter if I save the audio as 112 kbit/s MP3. Ain’t making that mistake again.
@binary1328 күн бұрын
mans still got it
@Bleenderhead8 күн бұрын
7:36 math typesetting jumpscare
@Bisqwit8 күн бұрын
Relax, that’s just Unicode.
@felipee22a8 күн бұрын
bisqwit, is this related to speech recognition? why?
@Bisqwit8 күн бұрын
Applications of DFT in audio processing include speech recognition, equalization, and audio compression. Applications of DFT in general are broader, including image recognition, speeding up large number multiplication, and solving partial differential equations.
@7369398 күн бұрын
Have you tried Rust for coding?
@Bisqwit8 күн бұрын
Not aside from the one isolated case I did in kzbin.info/www/bejne/bKvcppVjmJaLacU , and also some hacking of a save editor for Unreal engine games. I still feel it’s too stiff a language, although I appreciate the fresh winds of innovation.
@I-ONLY-BUILD-MECHS-AND-DUSTERS8 күн бұрын
Subbing for the * next to the variable type rather than the variable name.
@Bisqwit8 күн бұрын
Yeah, it is cleaner, although when defining multiple variables at once, this would not work correctly: void* pointer1, pointer2; In this kind contexts, I would place the asterisk next to the variable name.
@tune_m8 күн бұрын
Least snobby C++ programmer
@Bisqwit8 күн бұрын
@I-ONLY-BUILD-MECHS-AND-DUSTERS Is that name a RimWorld reference?
@adam78688 күн бұрын
Is there anything c++ cant do
@xbelanch8 күн бұрын
Are you sure you dont have a twin brother called Tsoding? Happy New Year🎉🎉!
@Bisqwit8 күн бұрын
Thanks, never heard of that name.
@xbelanch8 күн бұрын
@ check it out his videos. I think both of you have a lot in common!
@Logicatube8 күн бұрын
@Bisqwit Tsoding is a good KZbinr, I recommend watching him.
@user-x5v5b7 күн бұрын
I didn't understand anything, but it interesting
@scottperkey64668 күн бұрын
can i get a hell yeah
@Bisqwit8 күн бұрын
Thank you for the sentiment!
@kulliradio8 күн бұрын
Nää sinun videosi ovat mulle ihan hebreaa mutta tykkään silti katsoa miten c++ ammattilainen koodaa
@fburton85 күн бұрын
Wouldn’t a typical c++ professional use a lot more unnecessary frameworks and deeply nested class hierarchies? 😜
@Bisqwit5 күн бұрын
No, that’s NodeJS developers you are thinking about. @fburton8
@fburton85 күн бұрын
@@Bisqwit I stand corrected.
@RajaBabu-i8n9p8 күн бұрын
Bro please use , better front 🙏🙏 and also better theme.
@Bisqwit8 күн бұрын
Huh?
@0x90h8 күн бұрын
@@Bisqwit You could use that song Finland performed on Eurovision that would be awesome 😃
@provocativecheesecake8 күн бұрын
@@Bisqwit I believe OP was complaining about your font and color choices, which is, of course, wrong, and deserving of a hearty slap with a trout.
@Bisqwit8 күн бұрын
Although I appreciate the mIRC (or Asterix?) reference there, I think the comment was too ambiguous to really tell what it was about.