Return to blog page


Loud and clear CrazyAmphibian - 30/jun/2026

there's 2 things to talk about this time around. let's start with the first: an important announcment about the existing games.


after a lot of thought, i decided to make the existing games free, as in free beer.

This was because, well, for one, i wasn't making any money off of them anyways. and for two, i haven't been developing on them at all. and granted, you don't need to always update a game, but... i've had my fun with them, and i suppose now it's time for you to, too.

it's not like they were super innovative or novel. or even that high quality (in my defense, it was my first 2 games ever made). sure, they cost me some money to make, but money isn't everything, and i'd rather take the hit then keep worrying about letting down paying customers. now non-paying customers on the other hand, well that's nothing to worry about.

i joke, of course, but it will lift a weight off my back to not feel burdened by some three-quarters-baked projects i made years ago. I haven't given up all game development. i just realized that i should keep it on the side instead. that way i can make things that are higher quality, and that i'm more proud of. because truth be told, i don't feel proud of SSTD. maybe a bit more of Conformer, but... eh? it's hard to put into words, but it doesn't really matter.

either way, the old games are free, and i'll keep chipping away at a few projects in the background. project CM may see a revival, since i think i know what to do with that title now. and there's also another project that i'll get around to, too, probably, at some point, as can be seen above in the first part of this blog. they'll both probably take a while, but i have time. also i should probably use this blog more, huh? my bad. oh yeah also because it's the steam summer sale, or something, oh and it's the 4th of july and that means FREEdom.

actually upon going to steam to mark them free, i see that i have to fill out a form for this, so it'll take a few days for it to actually go through on steam. oops.

and now for the code development blog:

C++ is quite the language. Obtuse, unforgiving, fast, powerful. Its chunkiness makes me want to avoid it in most cases, but there's some cases where using it is almost mandatory.

One such case, and the topic of this blog, is audio processing. A typical audio stream runs at 44100 samples per second, per audio channel, with 16 bit depth, in stereo audio. That's a bitrate of roughly 172 kB/s, which is fairly high. on higher end setups, it can get towards 281, or even higher. And, in order to process that much data in real time without significant delays... you pretty much need a language like C(++). Sure, you could use a scripting language to process that, but you'd be spending a huge amount of the system's processing time on it, and add in further latency.

Miniaudio is a pretty good library, created by David Reid. It's multiplatform, open source, and provides direct PCM sample access. Basically, it removes the need to bother with annoying OS-specific audio code. This is quite nice when you're a bit of an idiot like me, and find Windows.h to be a nightmare. So used the library i did. Of course, you can't just call C++ code from a scripting language, first you have to build an API around it. but, we'll get there.

The first step to continuous audio playback is to set up a buffer for both input and output. This smoothes over timing inconsistencies, and means you don't have to be running all of the time. For this, a ring buffer is used. Ring buffers are interesting, occupying a fixed memory space that is cycled through with each write and read. They're incredibly fast and memory efficient, which is perfect for audio. Another benefit is that running behind means reading old data, which in most cases is undesirable, but in audio, will loop the currently playing sound, resulting in a less jarring mode of failure.

Ok, now that you have buffers, and some functions to push and pull data from them, you can now start thinking about making the API. The Lua API is... a bit clunky in some ways, but perfectly servicable, and you only need a couple of functions anyways. In all i made 5. One to pull microphone data, one to clear the playback buffer, one to modify the playback buffer, one to set the output volume, and one to check the buffer sample position. using these 5, a fairly robust and simple playback system can be made.

But now what? what do you do with all this audio routing? Well simple. send it over a network to players. All you have to do is create another packet type and send it over to the server and boom, you can send voice data to other players. Oh, but if only it were that simple. Because now with a network, you have to deal with packet loss and misorderings, not to mention latency to boot. So, for this we use... can you guess? another buffer! - but not a ring buffer. just a standard array buffer. This is because a ring buffer would not be very useful in this case, since the main issue isn't speed but rather reliability, and an ordered array lets us be a lot more structured than a ring.

This network-layer buffer seeks to do a few things. handle missing packets, reorder packets for correct playback, and maintain reliable timing with unreliable inputs. The buffer can accomplish most of this fairly well. The array is filled with packets in the correct order when they are received, and during each playback tick, the first element of the array is removed, and the other elements shifted forwards. If there is no avalible packet, the last good one will be repeated up to 3 times. And, if the incoming packet timing is too far ahead, it'll force jump the array forward to avoid latency drifts.

And there you go, now you've implemented voice chat in your game. As easy as that. And a project i've had on the backburner for too long will include it. Of course, the audio engine in that does not run at 44100hz, for both speed and networking reasons. instead, the quality has been significantly cut down, to 8000hz 8bit mono. This sounds pretty crunchy, but in a good way in my opinion, kinda like the xbox live lobbies of old. Such is the beautiy of limitations, they can be used for creative purposes.


Code snippet of the audio API and wrapper