summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorfbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-20 19:30:33 +0000
committerfbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-20 19:30:33 +0000
commit8511b2c7075a3fbc9b27652deaab575f9d5ea49d (patch)
treecc343886f722dd57ca1d060c95f8b0194cad894e /media
parent00e3f152083aea092353b3d284c368b48136f33c (diff)
downloadchromium_src-8511b2c7075a3fbc9b27652deaab575f9d5ea49d.zip
chromium_src-8511b2c7075a3fbc9b27652deaab575f9d5ea49d.tar.gz
chromium_src-8511b2c7075a3fbc9b27652deaab575f9d5ea49d.tar.bz2
Fold first 3 channels of multichannel instead of 5. Use fixed point.
BUG=none TEST=play a multichannel video, such as trek6.ogv. Voices should sound centered and music stereo. Review URL: http://codereview.chromium.org/304006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29550 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/audio/audio_util.cc183
-rw-r--r--media/audio/audio_util_unittest.cc24
2 files changed, 113 insertions, 94 deletions
diff --git a/media/audio/audio_util.cc b/media/audio/audio_util.cc
index c1c1bc8..8774a72 100644
--- a/media/audio/audio_util.cc
+++ b/media/audio/audio_util.cc
@@ -5,24 +5,90 @@
// Software adjust volume of samples, allows each audio stream its own
// volume without impacting master volume for chrome and other applications.
+// Implemented as templates to allow 8, 16 and 32 bit implementations.
+// 8 bit is unsigned and biased by 128.
+
#include "base/basictypes.h"
#include "base/logging.h"
#include "media/audio/audio_util.h"
namespace media {
-// Done as C for future assembly optimization and/or to move to different class.
-// TODO(fbarchard): add channels_in to allow number of channels to be reduced.
+namespace {
+
+// TODO(fbarchard): Convert to intrinsics for better efficiency.
-template<class Format>
-void AdjustVolumeInternal(Format* buf_out,
- int sample_count,
- float volume) {
+template<class Fixed>
+static int ScaleChannel(int channel, int volume) {
+ return static_cast<int>((static_cast<Fixed>(channel) * volume) >> 16);
+}
+
+template<class Format, class Fixed, int bias>
+void AdjustVolume(Format* buf_out,
+ int sample_count,
+ int fixed_volume) {
for (int i = 0; i < sample_count; ++i) {
- buf_out[i] = static_cast<Format>(buf_out[i] * volume);
+ buf_out[i] = static_cast<Format>(ScaleChannel<Fixed>(buf_out[i] - bias,
+ fixed_volume) + bias);
}
}
+// Channel order for AAC
+// From http://www.hydrogenaudio.org/forums/lofiversion/index.php/t40046.html
+
+static const int kChannel_C = 0;
+static const int kChannel_L = 1;
+static const int kChannel_R = 2;
+
+template<class Fixed, int min_value, int max_value>
+static int AddChannel(int val,
+ int adder) {
+ Fixed sum = static_cast<Fixed>(val) + static_cast<Fixed>(adder);
+ if (sum > max_value)
+ return max_value;
+ if (sum < min_value)
+ return min_value;
+ return static_cast<int>(sum);
+}
+
+// FoldChannels() downmixes multichannel (ie 5.1 Surround Sound) to Stereo.
+// Left and Right channels are preserved asis, and Center channel is
+// distributed equally to both sides. To be perceptually 1/2 volume on
+// both channels, 1/sqrt(2) is used instead of 1/2.
+// Fixed point math is used for efficiency. 16 bits of fraction and 8,16 or 32
+// bits of integer are used.
+// 8 bit samples are unsigned and 128 represents 0, so a bias is removed before
+// doing calculations, then readded for the final output.
+
+template<class Format, class Fixed, int min_value, int max_value, int bias>
+static void FoldChannels(Format* buf_out,
+ int sample_count,
+ const float volume,
+ int channels) {
+ Format* buf_in = buf_out;
+ const int center_volume = static_cast<int>(volume * 0.707f * 65536);
+ const int fixed_volume = static_cast<int>(volume * 65536);
+
+ for (int i = 0; i < sample_count; ++i) {
+ int center = static_cast<int>(buf_in[kChannel_C] - bias);
+ int left = static_cast<int>(buf_in[kChannel_L] - bias);
+ int right = static_cast<int>(buf_in[kChannel_R] - bias);
+
+ center = ScaleChannel<Fixed>(center, center_volume);
+ left = ScaleChannel<Fixed>(left, fixed_volume);
+ right = ScaleChannel<Fixed>(right, fixed_volume);
+
+ buf_out[0] = static_cast<Format>(
+ AddChannel<Fixed, min_value, max_value>(left, center) + bias);
+ buf_out[1] = static_cast<Format>(
+ AddChannel<Fixed, min_value, max_value>(right, center) + bias);
+
+ buf_out += 2;
+ buf_in += channels;
+ }
+}
+} // namespace
+
// AdjustVolume() does an in place audio sample change.
bool AdjustVolume(void* buf,
size_t buflen,
@@ -39,78 +105,27 @@ bool AdjustVolume(void* buf,
}
if (channels > 0 && channels <= 6 && bytes_per_sample > 0) {
int sample_count = buflen / bytes_per_sample;
+ const int fixed_volume = static_cast<int>(volume * 65536);
if (bytes_per_sample == 1) {
- AdjustVolumeInternal(reinterpret_cast<uint8*>(buf),
- sample_count,
- volume);
+ AdjustVolume<uint8, int32, 128>(reinterpret_cast<uint8*>(buf),
+ sample_count,
+ fixed_volume);
return true;
} else if (bytes_per_sample == 2) {
- AdjustVolumeInternal(reinterpret_cast<int16*>(buf),
- sample_count,
- volume);
+ AdjustVolume<int16, int32, 0>(reinterpret_cast<int16*>(buf),
+ sample_count,
+ fixed_volume);
return true;
} else if (bytes_per_sample == 4) {
- AdjustVolumeInternal(reinterpret_cast<int32*>(buf),
- sample_count,
- volume);
+ AdjustVolume<int32, int64, 0>(reinterpret_cast<int32*>(buf),
+ sample_count,
+ fixed_volume);
return true;
}
}
return false;
}
-// Channel order for AAC
-// From http://www.hydrogenaudio.org/forums/lofiversion/index.php/t40046.html
-// And Quicktime Pro, Movie Inspector
-const int kChannel_C = 0;
-const int kChannel_L = 1;
-const int kChannel_R = 2;
-const int kChannel_SL = 3;
-const int kChannel_SR = 4;
-const int kChannel_LFE = 5;
-
-template<class Format>
-Format ChannelsClampInternal(float val,
- const Format min_value,
- const Format max_value) {
- if (val > static_cast<float>(max_value)) {
- return max_value;
- }
- if (val < static_cast<float>(min_value)) {
- return min_value;
- }
- return static_cast<Format>(val);
-}
-
-template<class Format>
-void FoldChannelsInternal(Format* buf_out,
- int sample_count,
- float volume,
- int channels,
- const int min_value,
- const int max_value) {
- Format* buf_in = buf_out;
- // mid_value is to adjust excess 128 notation in unsigned 8 bit samples
- // to signed before adding channels.
- const int mid_value = (max_value + min_value + 1) / 2;
- const float kHalfPerceived = 0.707f; // 1/sqrt(2)
- for (int i = 0; i < sample_count; ++i) {
- float center_half = static_cast<float>(buf_in[kChannel_C] - mid_value) * kHalfPerceived;
- float left = static_cast<float>(buf_in[kChannel_L] - mid_value);
- float right = static_cast<float>(buf_in[kChannel_R] - mid_value);
- float surround_left = static_cast<float>(buf_in[kChannel_SL] - mid_value);
- float surround_right = static_cast<float>(buf_in[kChannel_SR] - mid_value);
- buf_out[0] = ChannelsClampInternal(
- (left + surround_left + center_half) * volume + mid_value,
- static_cast<Format>(min_value), static_cast<Format>(max_value));
- buf_out[1] = ChannelsClampInternal(
- (right + surround_right + center_half) * volume + mid_value,
- static_cast<Format>(min_value), static_cast<Format>(max_value));
- buf_out += 2;
- buf_in += channels;
- }
-}
-
bool FoldChannels(void* buf,
size_t buflen,
int channels,
@@ -121,27 +136,25 @@ bool FoldChannels(void* buf,
if (channels >= 5 && channels <= 6 && bytes_per_sample > 0) {
int sample_count = buflen / (channels * bytes_per_sample);
if (bytes_per_sample == 1) {
- FoldChannelsInternal(reinterpret_cast<uint8*>(buf),
- sample_count,
- volume,
- channels,
- 0, 255);
+ FoldChannels<uint8, int32, -128, 127, 128>(
+ reinterpret_cast<uint8*>(buf),
+ sample_count,
+ volume,
+ channels);
return true;
} else if (bytes_per_sample == 2) {
- FoldChannelsInternal(reinterpret_cast<int16*>(buf),
- sample_count,
- volume,
- channels,
- -32768,
- 32767);
+ FoldChannels<int16, int32, -32768, 32767, 0>(
+ reinterpret_cast<int16*>(buf),
+ sample_count,
+ volume,
+ channels);
return true;
} else if (bytes_per_sample == 4) {
- FoldChannelsInternal(reinterpret_cast<int32*>(buf),
- sample_count,
- volume,
- channels,
- 0x80000000,
- 0x7fffffff);
+ FoldChannels<int32, int64, 0x80000000, 0x7fffffff, 0>(
+ reinterpret_cast<int32*>(buf),
+ sample_count,
+ volume,
+ channels);
return true;
}
}
diff --git a/media/audio/audio_util_unittest.cc b/media/audio/audio_util_unittest.cc
index 4554f6e..c0ed0fc 100644
--- a/media/audio/audio_util_unittest.cc
+++ b/media/audio/audio_util_unittest.cc
@@ -14,7 +14,10 @@ namespace media {
TEST(AudioUtilTest, AdjustVolume_u8) {
// Test AdjustVolume() on 8 bit samples.
uint8 samples_u8[kNumberOfSamples] = { 4, 0x40, 0x80, 0xff };
- uint8 expected_u8[kNumberOfSamples] = { 2, 0x20, 0x40, 0x7f };
+ uint8 expected_u8[kNumberOfSamples] = { (4 - 128) / 2 + 128,
+ (0x40 - 128) / 2 + 128,
+ (0x80 - 128) / 2 + 128,
+ (0xff - 128) / 2 + 128 };
bool result_u8 = media::AdjustVolume(samples_u8, sizeof(samples_u8),
1, // channels.
sizeof(samples_u8[0]),
@@ -77,9 +80,12 @@ TEST(AudioUtilTest, AdjustVolume_s32) {
}
TEST(AudioUtilTest, FoldChannels_u8) {
- // Test AdjustVolume() on 16 bit samples.
+ // Test FoldChannels() on 8 bit samples.
uint8 samples_u8[6] = { 130, 100, 150, 70, 130, 170 };
- uint8 expected_u8[2] = { 43, 153 };
+ uint8 expected_u8[2] = { static_cast<uint8>((130 - 128) * 0.707 +
+ (100 - 128) + 128),
+ static_cast<uint8>((130 - 128) * 0.707 +
+ (150 - 128) + 128) };
bool result_u8 = media::FoldChannels(samples_u8, sizeof(samples_u8),
6, // channels.
sizeof(samples_u8[0]),
@@ -90,10 +96,10 @@ TEST(AudioUtilTest, FoldChannels_u8) {
}
TEST(AudioUtilTest, FoldChannels_s16) {
- // Test AdjustVolume() on 16 bit samples.
+ // Test FoldChannels() on 16 bit samples.
int16 samples_s16[6] = { 12, 1, 3, 7, 13, 17 };
- int16 expected_s16[2] = { static_cast<int16>(12 * .707 + 1 + 7),
- static_cast<int16>(12 * .707 + 3 + 13) };
+ int16 expected_s16[2] = { static_cast<int16>(12 * .707 + 1),
+ static_cast<int16>(12 * .707 + 3) };
bool result_s16 = media::FoldChannels(samples_s16, sizeof(samples_s16),
6, // channels.
sizeof(samples_s16[0]),
@@ -104,10 +110,10 @@ TEST(AudioUtilTest, FoldChannels_s16) {
}
TEST(AudioUtilTest, FoldChannels_s32) {
- // Test AdjustVolume() on 16 bit samples.
+ // Test FoldChannels() on 32 bit samples.
int32 samples_s32[6] = { 12, 1, 3, 7, 13, 17 };
- int32 expected_s32[2] = { static_cast<int16>(12 * .707 + 1 + 7),
- static_cast<int16>(12 * .707 + 3 + 13) };
+ int32 expected_s32[2] = { static_cast<int16>(12 * .707 + 1),
+ static_cast<int16>(12 * .707 + 3) };
bool result_s32 = media::FoldChannels(samples_s32, sizeof(samples_s32),
6, // channels.
sizeof(samples_s32[0]),