Skip to content

Commit

Permalink
Fix MP3 encoding for bit depths > 16
Browse files Browse the repository at this point in the history
lame_encode_buffer_long2() expects the values to be scaled
to fit the size of long, not a particular bit width.

Fixes #36
  • Loading branch information
sbooth committed Sep 13, 2020
1 parent c56d67c commit 4f66554
Showing 1 changed file with 13 additions and 9 deletions.
22 changes: 13 additions & 9 deletions Encoders/MP3Encoder.m
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,9 @@ - (void) encodeChunk:(const AudioBufferList *)chunk frameCount:(UInt32)frameCoun
for(channel = 0; channel < chunk->mBuffers[0].mNumberChannels; ++channel) {
channelBuffers[channel] = NULL;
}


unsigned long max_long_value_for_lame = 1UL << (8 * sizeof(long) - 1);

// Split PCM data into channels and convert to appropriate sample size for LAME
switch(_sourceBitsPerChannel) {

Expand All @@ -377,7 +379,7 @@ - (void) encodeChunk:(const AudioBufferList *)chunk frameCount:(UInt32)frameCoun
for(wideSample = sample = 0; wideSample < frameCount; ++wideSample) {
for(channel = 0; channel < chunk->mBuffers[0].mNumberChannels; ++channel, ++sample) {
// Rescale values to short
channelBuffers16[channel][wideSample] = (short)(((buffer8[sample] << 8) & 0xFF00) | (buffer8[sample] & 0xFF));
channelBuffers16[channel][wideSample] = (short)((buffer8[sample] / 128.f) * 32768);
}
}

Expand Down Expand Up @@ -411,18 +413,19 @@ - (void) encodeChunk:(const AudioBufferList *)chunk frameCount:(UInt32)frameCoun
channelBuffers32[channel] = calloc(frameCount, sizeof(long));
NSAssert(NULL != channelBuffers32[channel], NSLocalizedStringFromTable(@"Unable to allocate memory.", @"Exceptions", @""));
}

// Packed 24-bit data is 3 bytes, while unpacked is 24 bits in an int32_t
buffer8 = chunk->mBuffers[0].mData;
for(wideSample = sample = 0; wideSample < frameCount; ++wideSample) {
for(channel = 0; channel < chunk->mBuffers[0].mNumberChannels; ++channel) {
// Read three bytes and reconstruct them as a 32-bit BE integer
constructedSample = (int8_t)*buffer8++; constructedSample <<= 8;
constructedSample |= (uint8_t)*buffer8++; constructedSample <<= 8;
constructedSample |= (uint8_t)*buffer8++;

// Convert to 32-bit sample scaling
channelBuffers32[channel][wideSample] = (long)((constructedSample << 8) | (constructedSample & 0x000000ff));

// lame_encode_buffer_long2() expects the values to be scaled to fit the size of long, not a particular bit width
// Specifically in the range 2^(8*sizeof(long)-1)
// Which for 32-bit longs = 2147483648 (0x80000000), for 64-bit longs = 9223372036854775808 (0x8000000000000000)
channelBuffers32[channel][wideSample] = (long)((constructedSample / 8388608.f) * max_long_value_for_lame);
}
}

Expand All @@ -437,11 +440,12 @@ - (void) encodeChunk:(const AudioBufferList *)chunk frameCount:(UInt32)frameCoun
channelBuffers32[channel] = calloc(frameCount, sizeof(long));
NSAssert(NULL != channelBuffers32[channel], NSLocalizedStringFromTable(@"Unable to allocate memory.", @"Exceptions", @""));
}

buffer32 = chunk->mBuffers[0].mData;
for(wideSample = sample = 0; wideSample < frameCount; ++wideSample) {
for(channel = 0; channel < chunk->mBuffers[0].mNumberChannels; ++channel, ++sample) {
channelBuffers32[channel][wideSample] = (long)OSSwapBigToHostInt32(buffer32[sample]);
// See comment above about expected scaling for lame_encode_buffer_long2()
channelBuffers32[channel][wideSample] = (long)((OSSwapBigToHostInt32(buffer32[sample]) / 2147483648.f) * max_long_value_for_lame);
}
}

Expand Down

0 comments on commit 4f66554

Please sign in to comment.