Gain and Stereo - richardjwild/arctracker GitHub Wiki
In the previous chapter I had threatened to extract the gain/volume adjustment and stereo panning into its own module, so I decided the time had come to do just that. There were quite a lot of changes in that commit, but in a nutshell I created a new compilation unit gain.c with associated header file defining these:
#include "play_mod.h"
typedef struct
{
long l;
long r;
} stereo_frame_t;
stereo_frame_t apply_gain(unsigned char mu_law_sample, channel_info *voice);
and I altered write_audio.c to use the new apply_gain function, which cleaned up the code nicely.
Next I made gain.c responsible for the master gain. Then I moved responsibility for stereo panning there as well, which meant that I no longer needed to store left_gain and right_gain in the channel_info struct and could replace it with a number indicating the panning (1 for hard left, 7 for hard right).
I never did like the name of that log_lin_tab.h file so I renamed it to mu_law.h and followed that by a bit more fiddling with names. This had nothing to do with gain or stereo, but I moved some static variable declarations from write_audio.h to write_audio.c because (I didn't realise) that they were "public" in the header file and would clash with similarly-named things defined in other header files, which I didn't want, I wanted them to be name-scoped to the compilation unit.
Finally, I realised that I could gain a further simplification of the code if I redefined the channel buffer as an array of stereo_frame_t rather than long. This meant I could replace the channel_buffer_stride_length variable because it was now simply channels - 1, and it also made the write_frames_for_channel function look very nice:
void write_frames_for_channel(channel_info *voices, const int channel, const long frames_to_fill)
{
channel_info *voice = voices + channel;
long offset = buffer_offset_for(channel);
unsigned char* resample_buffer = resample(voice, frames_to_fill);
for (long frame = 0; frame < frames_to_fill; frame++)
{
unsigned char mu_law = resample_buffer[frame];
stereo_frame_t stereo_frame = apply_gain(mu_law, voice);
channel_buffer[offset] = stereo_frame;
offset += channels;
}
}