blob: 6867915a7cffd25cfee08220c943cb4308768104 [file] [log] [blame]
// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef AUDIOTEST_UTIL_H_
#define AUDIOTEST_UTIL_H_
#include <limits>
#include <iostream>
#include <vector>
#include "common.h"
#define BYTE(X, i) ((reinterpret_cast<unsigned char *>(&X))[i])
using std::vector;
namespace autotest_client {
namespace audio {
// Returns the square of absolute value of complex number.
inline double SquareAbs(const double real, const double imaginary) {
return real * real + imaginary * imaginary;
}
// Gets the number of frames needed, w.r.t. bufsize.
inline unsigned BufsizeToFrames(size_t bufsize,
SampleFormat format,
int num_channels) {
return bufsize / (format.bytes() * num_channels);
}
// Writes a sample to the char buffer with the given data type.
// Sample should be a value between 1.0 ~ -1.0.
// Returns the next position of the buffer.
template <typename T>
void *WriteSample(double sample, void *buf) {
// Handles unsigned type.
if (std::is_unsigned<T>::value) {
sample += 1.0;
sample /= 2.0;
}
T* sample_data = reinterpret_cast<T*>(buf);
*sample_data = sample * std::numeric_limits<T>::max();
return sample_data + 1;
}
// Detects big endian at run time.
inline bool IsBigEndian() {
union {
uint32_t i;
char c[4];
} combine = {0x01020304};
return combine.c[0] == 1;
}
// Writes a sample to the char buffer with the given data type.
// Sample should be a value between 1.0 ~ -1.0.
// Returns the next position of the buffer.
inline void *WriteSample(double sample, void *buf, SampleFormat format) {
if (format.type() == SampleFormat::kPcmU8) {
return WriteSample<unsigned char>(sample, buf);
} else if (format.type() == SampleFormat::kPcmS16) {
return WriteSample<int16_t>(sample, buf);
} else if (format.type() == SampleFormat::kPcmS24) {
unsigned char* sample_data = reinterpret_cast<unsigned char*>(buf);
int32_t value = sample * (1 << 23); // 1 << 23 24-bit signed max().
if (IsBigEndian()) {
for (int i = 0; i < 3; i++) {
sample_data[i] = BYTE(value, i+1);
}
} else {
for (int i = 0; i < 3; i++) {
sample_data[i] = BYTE(value, i);
}
}
return sample_data + 3;
} else if (format.type() == SampleFormat::kPcmS32) {
return WriteSample<int32_t>(sample, buf);
}
// Returns NULL, which should crash the caller.
std::cerr << "Unknown format when doing conversion." << std::endl;
assert(false);
return NULL;
}
// Reads from raw data and returns a sample between 1.0 ~ -1.0.
template<typename T>
inline double ReadSample(T data) {
double val = static_cast<double>(data) / std::numeric_limits<T>::max();
if (std::numeric_limits<T>::min() == 0) {
val = val * 2.0 - 1.0;
}
return val;
}
// Reads from raw data and converts them to samples with double type.
template<typename T>
inline void FramesToSamples(void* data,
int num_frames,
int num_channels,
vector< vector<double> > *sample_ptr) {
vector< vector<double> >& mag = *sample_ptr;
T *ptr = static_cast<T*>(data);
for (int n = 0; n < num_frames; n++) {
for (int c = 0; c < num_channels; c++) {
mag[c][n] = ReadSample<T>(*(ptr++));
}
}
}
// Reads from raw data and converts them to samples with double type.
inline void FramesToSamples(void* data,
int bufsize,
int num_channels,
vector< vector<double> > *sample_ptr,
SampleFormat format) {
unsigned num_frames = bufsize / (format.bytes() * num_channels);
if (format.type() == SampleFormat::kPcmU8) {
FramesToSamples<unsigned char>
(data, num_frames, num_channels, sample_ptr);
} else if (format.type() == SampleFormat::kPcmS16) {
FramesToSamples<int16_t>
(data, num_frames, num_channels, sample_ptr);
} else if (format.type() == SampleFormat::kPcmS24) {
auto& mag = *sample_ptr;
unsigned char *ptr = static_cast<unsigned char*>(data);
for (unsigned n = 0; n < num_frames; n++) {
for (int c = 0; c < num_channels; c++) {
int32_t value = 0;
if (IsBigEndian()) {
for (int i = 2; i >= 0; i--)
value |= (static_cast<int>(*(ptr++))) << (8 * i);
} else {
for (int i = 0; i < 3; i++)
value |= (static_cast<int>(*(ptr++))) << (8 * i);
}
mag[c][n] = static_cast<double>(value) / (1 << 23);
}
}
} else if (format.type() == SampleFormat::kPcmS32) {
FramesToSamples<int32_t>
(data, num_frames, num_channels, sample_ptr);
}
}
} // namespace audio
} // namespace autotest_client
#endif // AUDIOTEST_UTIL_H_