[63] Pretty Cool Modulation
- Conlan Walker

- Dec 29, 2022
- 3 min read
The audio engine should be done at this point. It currently has just about every feature I want, and I haven't really found any real unwanted behavior with it.
To start the work week off, I immediately changed the .mua header. The biggest change made was the replacement of dataSize, which is now in the same 16 byte space as numSamples, which makes things easier to see when viewed with a hex editor:

I also made a few changes to muaReadFile(), as shown here:

I wanted my audio engine to support every common form of PCM audio data, whether it be floats, or 8->32 bit signed and unsigned integers. The best way I've found to enable this is to internally convert all samples to floats. Here's a test which demonstrates conversion of an input audio stream of unsigned 8-bit samples:

A struct is used to store and handle audio clip info, in the form of AudioElement.

An array of these things is used to facilitate proper mixing of audio. Each element in this array I call a track. If the data portion of an AudioElement in the array is NULL, that "track" is considered inactive.
If there are no inactive (aka available) tracks to be found, audio clips can't be queued for playback. I made a diagram to demonstrate how this works, shown below:

The numbers (y axis) correspond to track slot numbers. Those bars with the dots are depictions of audio clips, with varying durations. The red and green spots in the timeline show whether or not you can queue more audio clips at each point.
If track 1 is occupied, it will try track 2, then 3, and so on until it
either finds a vacant track, or it runs out of tracks to check. There are 4 tracks shown here, but in practice it's set to 32 total tracks, as that should cover any reasonable application (it can be set to more or less, but 32 seems good enough for what I want to do).
Here's a list of the current list of audio functions, as shown in kaudio.h:

Now for the tests where you can actually hear something. I have two to show this time.
The initialization procedure is pretty much just the boilerplate SDL audio one, except the userdata section of the audio spec is tied to the number of active tracks for any given invocation of the audio callback.

The first test I did involves a few things, which includes mixing of two audio tracks, clips that can loop forever, as well as changing the volume of those two tracks over time.

Here are the two individual tracks being mixed and looped as heard in the video below:
Most of these tests (including this one) use music/sounds from Yume 2kki.
This is due to the (generally) short length of its songs, and wide variety of sample rates and PCM data types. Also, most songs are supposed to seamlessly loop, which is a .mua feature.
This next image performs basically the same action, but it instead uses the interface functions, rather than directly manipulating the audio track struct array:

The next one is a stress test to see what happens when audio clips are spam-queued.

For the test, I set the total tracks to 4, like the diagram. This means that there should be no more than 4 audio clips playing at once, and those 4 shouldn't be cut-off at any point before they finish.
I also used the Tim Allen grunt here because it was funny.
The current feature list I could come up with is as follows:
Channel-independent adjustable volume
Channel-independent volume gradients (volume change over a specified time span)
Variable audio speed
Universal sample rate conversion via linear interpolation
Variable looping of audio clips
Adjustable device sample rate, stream buffer size, and track count
Management of active tracks
Hard clipping of stream buffer
Support for most PCM audio data types
There might be more, but I can't pull any more off the top of my head.

To finish this post, here's a printout of the current line count for everything as it stands now.
Next week I'll look into using libmikmod to handle music, as I'd like to only use this audio engine for things like short sound effects.
(I'm hoping that there's no device conflicts with mikmod and SDL audio to worry about.)

![[158] Most Important Brick in the Least Important Wall](https://static.wixstatic.com/media/df100d_f70be6ae4318455fbbc605cd1069c6ee~mv2.jpg/v1/fill/w_980,h_410,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/df100d_f70be6ae4318455fbbc605cd1069c6ee~mv2.jpg)
![[157] Mail Order Sacrifice](https://static.wixstatic.com/media/df100d_e284fa6c51b04524bab9d3cf9f1f6441~mv2.png/v1/fill/w_980,h_382,al_c,q_90,usm_0.66_1.00_0.01,enc_avif,quality_auto/df100d_e284fa6c51b04524bab9d3cf9f1f6441~mv2.png)
![[156] Moat of Babble](https://static.wixstatic.com/media/df100d_091e451794b14aecb494a16c15c966c3~mv2.png/v1/fill/w_980,h_705,al_c,q_90,usm_0.66_1.00_0.01,enc_avif,quality_auto/df100d_091e451794b14aecb494a16c15c966c3~mv2.png)
Comments