I'm trying to convert 16 bit stereo sound from a WAVE file to 16 bit mono sound, but I'm having some struggle. I've tried to convert 8 bit stereo sound to mono and it's working great. Here's the piece of code for that:
if( bitsPerSample == 8 )
{
dataSize /= 2;
openALFormat = AL_FORMAT_MONO8;
for( SizeType i = 0; i < dataSize; i++ )
{
pData[ i ] = static_cast<Uint8>(
( static_cast<Uint16>( pData[ i * 2 ] ) +
static_cast<Uint16>( pData[ i * 2 + 1 ] ) ) / 2
);
}
But, now I'm trying to do pretty much the same with 16 bit audio, but I just can't get it to work. I can just hear some kind of weird noise. I've tried to set "monoSample" to "left"(Uint16 monoSample = left;) and the audio data from that channel works very well. The right channel as well. Can anyone of you see what I'm doing wrong? Here's the code(pData is an array of bytes):
if( bitsPerSample == 16 )
{
dataSize /= 2;
openALFormat = AL_FORMAT_MONO16;
for( SizeType i = 0; i < dataSize / 2; i++ )
{
Uint16 left = static_cast<Uint16>( pData[ i * 4 ] ) |
( static_cast<Uint16>( pData[ i * 4 + 1 ] ) << 8 );
Uint16 right = static_cast<Uint16>( pData[ i * 4 + 2 ] ) |
( static_cast<Uint16>( pData[ i * 4 + 3 ] ) << 8 );
Uint16 monoSample = static_cast<Uint16>(
( static_cast<Uint32>( left ) +
static_cast<Uint32>( right ) ) / 2
);
// Set the new mono sample.
pData[ i * 2 ] = static_cast<Uint8>( monoSample );
pData[ i * 2 + 1 ] = static_cast<Uint8>( monoSample >> 8 );
}
}
Windows lets you convert stereo sound into a single channel so you can hear everything, even if you're using just one headphone. Select the Start button, then select Settings > Accessibility > Audio, and then switch on the Mono audio toggle.
Converting a mono file into a stereo file produces an audio file that contains the same material in both channels, for example for further processing into real stereo. Converting a stereo file into a mono file mixes the stereo channels to a mono channel.
This menu also lets you convert a stereo track to a mono track containing only one of the channels: Choose "Split Stereo to Mono" from the Track Dropdown Menu if your stereo track is not already split into separate tracks. Close the unwanted track using the X button at the top left of the Track Control Panel.
In the General Preferences tab, click on Import Settings, located towards the bottom. Click on the menu next to Import Using > WAV Encoder. Then click to change Setting > Custom and a new window will open. In the WAV Encoder window, change the Sample Rate to 44.100 kHz and Sample Size to 16-bit.
In a 16 bit stereo WAV file, each sample is 16 bits, and the samples are interleaved. I'm not sure why you're using a bitwise OR, but you can just retrieve the data directly without having to shift. The below non-portable code (assumes sizeof(short) == 2) illustrates this.
unsigned size = header.data_size;
char *data = new char[size];
// Read the contents of the WAV file in to data
for (unsigned i = 0; i < size; i += 4)
{
short left = *(short *)&data[i];
short right = *(short *)&data[i + 2];
short monoSample = (int(left) + right) / 2;
}
Also, while 8 bit WAV files are unsigned, 16 bit WAV files are signed. To average them, make sure you store it in an appropriately sized signed type. Note that one of the samples is promoted to an int temporarily to prevent overflow.
As has been pointed out in the comments below by Stix, simple averaging may not give the best results. Your mileage may vary.
In addition, Greg Hewgill correctly noted that this assumes that the machine is little-endian.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With