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.
@blacklion7916 күн бұрын
@@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
@emperorpalpatine608017 күн бұрын
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.
@nrdesign199117 күн бұрын
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.
@Bisqwit17 күн бұрын
Very true!
@pavelperina762916 күн бұрын
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.
@nrdesign199116 күн бұрын
@@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.
@bas777ien17 күн бұрын
He dropped the best programming example and thought we wouldn't notice
@tenaibms17 күн бұрын
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.
@Bisqwit17 күн бұрын
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.
@yankilo16 күн бұрын
It's a pleasure to hear from you again, Joel. Happy New Year!
@shurgars16 күн бұрын
Lovely. A programming video from Bisqwit!! You meant a lot to me pursuing coputer science professionally about 7 years ago.
@literallynull17 күн бұрын
As a radio engineering undergrad, this is simply brilliant!
@TheRallyFTW16 күн бұрын
Bisqwit MIGHT be one of the coders of all time
@Bisqwit16 күн бұрын
Considering all the comments posted on my videos so far, yours was one of them.
@VanosTurbo21 сағат бұрын
Yes! You are back and it compiled on the first attempt :)
@poohandim16 күн бұрын
I’ve always like your videos. Never give up!
@georgeallen748716 күн бұрын
This is the type of project that is a Bisqwit classic. C++, SDL, and some very technical subject.
@thsstphok793717 күн бұрын
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!
@fburton814 күн бұрын
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’.
@plantwateringcitizen878717 күн бұрын
2025 Christmas present delivered very early!! Thank you, Bisqwit - happy new year!
@Bisqwit17 күн бұрын
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.
@vaibhavmishra517917 күн бұрын
Happy New Year Bisqwit!
@Asdayasman15 күн бұрын
5:35 WHY lmao. Good to see you back. Could I please, once again, ask for a conclusion to the compiler project? Love you.
@Bisqwit15 күн бұрын
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…
@Asdayasman15 күн бұрын
@@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.
@BlizzetaNet16 күн бұрын
BISQWIIIIIT! ❤❤❤❤❤ I cant tell you how much I love SDL, and this is another reason. Great video!
@Humble_Electronic_Musician17 күн бұрын
Yay, a new Bisqwit video! God bless you!
@verysoftwares17 күн бұрын
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 🙏
@Rand008116 күн бұрын
Welcome back. I remember I needed an FFT explanation, but now I don't remember for which project.
@alfaalfa9916 күн бұрын
Long time no see you. Thanks for the video.
@vycdev17 күн бұрын
Happy New Year!!
@harriehausenman862317 күн бұрын
"tool-assisted education video" 😄 love it
@placeholderhandlehere16 күн бұрын
It's a good day when Bisqwit uploads
@Mro1976517 күн бұрын
Thank you cooley and tukey for your algorithm.
@tonym585717 күн бұрын
Happy new year with a video 👌💪
@axelkoster17 күн бұрын
Happy New Year
@wjdeh1011017 күн бұрын
Happy New Year!!!
@movization17 күн бұрын
Happy New Year!
@jh0nny_350z17 күн бұрын
My god, you are so good!
@Bisqwit16 күн бұрын
I try to be… Thanks for writing!
@travelthetropics619017 күн бұрын
Happy new year! 😊
@bas777ien17 күн бұрын
Babe wake up, new programming masterpiece dropped
@Capewearer15 күн бұрын
Legend is back!
@japedr15 күн бұрын
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!
@Bisqwit15 күн бұрын
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!
@japedr14 күн бұрын
@@Bisqwit oh, I didn't realize that, thanks for the explanation!
@kadavr31415 күн бұрын
New Biswit video? HUMANITY RESTORED \[T]/
@elultimopujilense17 күн бұрын
Awesome!
@sergioarellano73474 күн бұрын
Hello Bisqwit im glad u are back! :) i do have a question just curious, do you use Rust? What do you think about it ?
@Bisqwit4 күн бұрын
I have not used it aside from the one isolated case I did in kzbin.info/www/bejne/bKvcppVjmJaLacU , and also modifying a save editor for Unreal engine games that had been written in Rust. I still feel it’s too stiff a language, although I appreciate the fresh winds of innovation.
@HarhaMedia17 күн бұрын
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.
@steingamedev16 күн бұрын
What IDE do you use? It looks amazing! Edit: Never mind I found your video on it. I'll check it out.
@Veso26616 күн бұрын
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
@Bisqwit16 күн бұрын
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.
@Veso26616 күн бұрын
@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
@Bisqwit16 күн бұрын
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.
@Veso26616 күн бұрын
@@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)
@GrepGaming16 күн бұрын
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!
@anon_y_mousse13 күн бұрын
I'm curious as to why you use .cc and .hh for C++ file extensions instead of the more conventional .cpp and .hpp ?
@Bisqwit13 күн бұрын
"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_mousse13 күн бұрын
@@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.
@OrangeShellGaming13 күн бұрын
@@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_mousse13 күн бұрын
@@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.
@OrangeShellGaming12 күн бұрын
@@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.
@AlessioSangalli16 күн бұрын
Why would you sample at 96kHz? What kind of microphone do you use that has such a large bandwidth?
@Bisqwit16 күн бұрын
Hmm, my Blue Yeti Pro can in fact record at 192 kHz, 24-bit resolution.
@AlessioSangalli15 күн бұрын
@ 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)
@Bisqwit15 күн бұрын
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).
@AlessioSangalli14 күн бұрын
@@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
@Bisqwit13 күн бұрын
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.
@adam786816 күн бұрын
Is there anything c++ cant do
@youtubeenjoyer174317 күн бұрын
You lost me at a macro defining a struct with virtual methods inheriting another struct. That is some crazy++ right there.
@Bisqwit17 күн бұрын
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.
@srccde17 күн бұрын
@@Bisqwit The different default visibility also applies to inheritance, though. struct A {}; class B : A {}; // private inheritance struct C : A {}; // public inheritance
@Bisqwit17 күн бұрын
Thanks! I didn’t actually know that part.
@MissNorington17 күн бұрын
@@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!
@Bisqwit17 күн бұрын
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).
@afmikasenpai17 күн бұрын
Neat implementation! 7:39 Is that rendered LaTeX at line 28?
@Bisqwit17 күн бұрын
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.
@afmikasenpai17 күн бұрын
@@Bisqwit Ahhh the N-1 threw me off a bit, it rendered so nicely. Thanks for the answer!
@Bisqwit17 күн бұрын
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…
@ZomB198616 күн бұрын
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)
@Bisqwit16 күн бұрын
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.
@qaz1wsx2edc113 күн бұрын
Hello, i have watched a couple of your videos now and wonder about the os you are using. did you make it yourself?
@Bisqwit13 күн бұрын
I used Linux. But you only see fullscreened programs in this video.
@vomaxHELLnO17 күн бұрын
I wish I had these superpowers
@0x90h17 күн бұрын
These superpowers are earned not given.
@binary13217 күн бұрын
mans still got it
@73693916 күн бұрын
Have you tried Rust for coding?
@Bisqwit16 күн бұрын
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.
@pavelperina762916 күн бұрын
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.
@Bisqwit16 күн бұрын
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.
@felipee22a17 күн бұрын
bisqwit, is this related to speech recognition? why?
@Bisqwit17 күн бұрын
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.
@Bleenderhead16 күн бұрын
7:36 math typesetting jumpscare
@Bisqwit16 күн бұрын
Relax, that’s just Unicode.
@xbelanch17 күн бұрын
Are you sure you dont have a twin brother called Tsoding? Happy New Year🎉🎉!
@Bisqwit17 күн бұрын
Thanks, never heard of that name.
@xbelanch17 күн бұрын
@ check it out his videos. I think both of you have a lot in common!
@Logicatube17 күн бұрын
@Bisqwit Tsoding is a good KZbinr, I recommend watching him.
@I-ONLY-BUILD-MECHS-AND-DUSTERS17 күн бұрын
Subbing for the * next to the variable type rather than the variable name.
@Bisqwit17 күн бұрын
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_m16 күн бұрын
Least snobby C++ programmer
@Bisqwit16 күн бұрын
@I-ONLY-BUILD-MECHS-AND-DUSTERS Is that name a RimWorld reference?
@user-x5v5b15 күн бұрын
I didn't understand anything, but it interesting
@scottperkey646617 күн бұрын
can i get a hell yeah
@Bisqwit16 күн бұрын
Thank you for the sentiment!
@kulliradio17 күн бұрын
Nää sinun videosi ovat mulle ihan hebreaa mutta tykkään silti katsoa miten c++ ammattilainen koodaa
@fburton814 күн бұрын
Wouldn’t a typical c++ professional use a lot more unnecessary frameworks and deeply nested class hierarchies? 😜
@Bisqwit13 күн бұрын
No, that’s NodeJS developers you are thinking about. @fburton8
@fburton813 күн бұрын
@@Bisqwit I stand corrected.
@RajaBabu-i8n9p17 күн бұрын
Bro please use , better front 🙏🙏 and also better theme.
@Bisqwit17 күн бұрын
Huh?
@0x90h17 күн бұрын
@@Bisqwit You could use that song Finland performed on Eurovision that would be awesome 😃
@provocativecheesecake16 күн бұрын
@@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.
@Bisqwit16 күн бұрын
Although I appreciate the mIRC (or Asterix?) reference there, I think the comment was too ambiguous to really tell what it was about.