24-bit Gain

This post isn’t specifically about Audacity but is about a project I’m working on with PortAudio.

I’m writing a program which is essentially a “mic boost” program. It uses PortAudio and is written in PureBasic. The program reads audio samples from PortAudio’s buffer and multiplies the sample by a gain factor, thereby increasing or decreasing the audio level.

I have the program working great with 16-bit audio samples, but 24 bits, not so much.

I am able to read and write 24-bit samples and everything works great as long as I don’t apply any gain, that is, if the gain is unity (1). When I try to apply gain to a sample, the audio is present but it takes on an undesirable crackling sound. I’m not sure how to deal with this.

I am reading a 32-bit sample from the buffer, then shifing off the 8 most-significant bits and then shifting back by 8 bits to make it appear as a signed 24-bit integer. This 24-bit integer is cast as a float; I then divide it by 8388607 ((2 ^ 23) - 1) to confine it to a range of -1.0 to +1.0. The gain is applied to this float which is multiplied by 8388607 to get it back to a signed 24-bit number. Again, when the gain is unity (1) all is well. When the gain is other than unity, there is a “scratchy” noise behind the desired sound.

I may be writing the 24-bit sample back to the buffer incorrectly, but I have to figure out how to extract one 16-bit word and an 8-bit byte from the 24-bit sample, or three 8-bit bytes.

Am I doing this all wrong or am I on the right track? Does anyone have any better ideas?

Thank you.

Is that float or integer?

Integer

Perhaps you have an error in the endianness.

Try feeding a known signal, such as a sawtooth wave, through your system and look at what comes out - that may give an indication of what is going wrong.

One little wrinkle involves the conversion to float:

If sample >= 0; sample /= 8388607

else sample /= 8388608

Still looking into endianness.

Another clue: PortAudio deals with packed 24-bit samples.

http://portaudio.com/docs/v19-doxydocs/portaudio_8h.html

I’ve been banging away at this for a week and it works perfectly as long as the gain is unity. At other than unity gain the audio becomes scratchy. The program works wonderfully with 16-bit samples but goes to pieces with 24-bit samples.

How does Audacity scale 24-bit samples up or down without getting artifacts?

Adjusting the volume of a digital data stream is non-trivial because there is a hidden requantization (reduction in precision) of the input data.

Audacity processes entirely in 32-bit float format.

PortAudio gets integer samples from the audio hardware. At some point those integers are converted to floats.

Yes, but PortAudio’s 24 bit sample format is different from Audacity’s int24Sample format, so Audacity makes PortAudio return float samples when recording in 24-bit samples. See AudioIO.cpp.