Commit 7b74c2cc authored by Stefan Westerfeld's avatar Stefan Westerfeld

Support big endian / little endian format.

Signed-off-by: Stefan Westerfeld's avatarStefan Westerfeld <stefan@space.twc.de>
parent b19ef4a2
......@@ -149,6 +149,17 @@ parse_format (const string& str)
exit (1);
}
RawFormat::Endian
parse_endian (const string& str)
{
if (str == "little")
return RawFormat::Endian::LITTLE;
if (str == "big")
return RawFormat::Endian::BIG;
error ("audiowmark: unsupported endianness '%s'\n", str.c_str());
exit (1);
}
void
parse_options (int *argc_p,
char **argv_p[])
......@@ -241,6 +252,22 @@ parse_options (int *argc_p,
Params::raw_input_format.set_bit_depth (b);
Params::raw_output_format.set_bit_depth (b);
}
else if (check_arg (argc, argv, &i, "--raw-input-endian", &opt_arg))
{
auto e = parse_endian (opt_arg);
Params::raw_input_format.set_endian (e);
}
else if (check_arg (argc, argv, &i, "--raw-output-endian", &opt_arg))
{
auto e = parse_endian (opt_arg);
Params::raw_output_format.set_endian (e);
}
else if (check_arg (argc, argv, &i, "--raw-endian", &opt_arg))
{
auto e = parse_endian (opt_arg);
Params::raw_input_format.set_endian (e);
Params::raw_output_format.set_endian (e);
}
else if (check_arg (argc, argv, &i, "--raw-channels", &opt_arg))
{
int c = atoi (opt_arg);
......
......@@ -4,7 +4,7 @@
using std::vector;
template<int BIT_DEPTH>
template<int BIT_DEPTH, RawFormat::Endian ENDIAN>
class RawConverterImpl : public RawConverter
{
public:
......@@ -12,24 +12,62 @@ public:
void from_raw (const std::vector<unsigned char>& bytes, std::vector<float>& samples);
};
template<int BIT_DEPTH>
static RawConverter *
create_with_bits (const RawFormat& raw_format, Error& error)
{
switch (raw_format.endian())
{
case RawFormat::LITTLE: return new RawConverterImpl<BIT_DEPTH, RawFormat::LITTLE>();
case RawFormat::BIG: return new RawConverterImpl<BIT_DEPTH, RawFormat::BIG>();
}
error = Error ("unsupported endianness");
return nullptr;
}
RawConverter *
RawConverter::create (const RawFormat& raw_format, Error& error)
{
error = Error::Code::NONE;
switch (raw_format.bit_depth())
{
case 16: return new RawConverterImpl<16>();
case 24: return new RawConverterImpl<24>();
case 16: return create_with_bits<16> (raw_format, error);
case 24: return create_with_bits<24> (raw_format, error);
default: error = Error ("unsupported bit depth");
return nullptr;
}
}
template<int BIT_DEPTH>
template<int BIT_DEPTH, RawFormat::Endian ENDIAN>
constexpr std::array<int, 3>
make_endian_shift ()
{
if (BIT_DEPTH == 16)
{
if (ENDIAN == RawFormat::Endian::LITTLE)
return { 16, 24, -1 };
else
return { 24, 16, -1 };
}
if (BIT_DEPTH == 24)
{
if (ENDIAN == RawFormat::Endian::LITTLE)
return { 8, 16, 24 };
else
return { 24, 16, 8 };
}
}
template<int BIT_DEPTH, RawFormat::Endian ENDIAN>
void
RawConverterImpl<BIT_DEPTH>::to_raw (const vector<float>& samples, vector<unsigned char>& output_bytes)
RawConverterImpl<BIT_DEPTH, ENDIAN>::to_raw (const vector<float>& samples, vector<unsigned char>& output_bytes)
{
output_bytes.resize (BIT_DEPTH / 8 * samples.size());
constexpr int sample_width = BIT_DEPTH / 8;
constexpr auto eshift = make_endian_shift<BIT_DEPTH, ENDIAN>();
output_bytes.resize (sample_width * samples.size());
unsigned char *ptr = output_bytes.data();
for (size_t i = 0; i < samples.size(); i++)
{
......@@ -39,40 +77,37 @@ RawConverterImpl<BIT_DEPTH>::to_raw (const vector<float>& samples, vector<unsign
const int sample = lrint (bound<double> (min_value, samples[i] * norm, max_value));
if (BIT_DEPTH == 16)
{
// write 16-bit little endian value
output_bytes[i * 2] = sample >> 16;
output_bytes[i * 2 + 1] = sample >> 24;
}
else if (BIT_DEPTH == 24)
{
// write 24-bit little endian value
output_bytes[i * 3] = sample >> 8;
output_bytes[i * 3 + 1] = sample >> 16;
output_bytes[i * 3 + 2] = sample >> 24;
}
if (eshift[0] >= 0)
ptr[0] = sample >> eshift[0];
if (eshift[1] >= 0)
ptr[1] = sample >> eshift[1];
if (eshift[2] >= 0)
ptr[2] = sample >> eshift[2];
ptr += sample_width;
}
}
template<int BIT_DEPTH>
template<int BIT_DEPTH, RawFormat::Endian ENDIAN>
void
RawConverterImpl<BIT_DEPTH>::from_raw (const vector<unsigned char>& input_bytes, vector<float>& samples)
RawConverterImpl<BIT_DEPTH, ENDIAN>::from_raw (const vector<unsigned char>& input_bytes, vector<float>& samples)
{
const unsigned char *ptr = input_bytes.data();
const int sample_width = BIT_DEPTH / 8;
constexpr int sample_width = BIT_DEPTH / 8;
constexpr auto eshift = make_endian_shift<BIT_DEPTH, ENDIAN>();
samples.resize (input_bytes.size() / sample_width);
const double norm = 1.0 / 0x80000000LL;
for (size_t i = 0; i < samples.size(); i++)
{
int s32;
if (BIT_DEPTH == 16)
s32 = (ptr[1] << 24) + (ptr[0] << 16);
int s32 = 0;
if (BIT_DEPTH == 24)
s32 = (ptr[2] << 24) + (ptr[1] << 16) + (ptr[0] << 8);
if (eshift[0] >= 0)
s32 += ptr[0] << eshift[0];
if (eshift[1] >= 0)
s32 += ptr[1] << eshift[1];
if (eshift[2] >= 0)
s32 += ptr[2] << eshift[2];
samples[i] = s32 * norm;
ptr += sample_width;
......
......@@ -36,6 +36,12 @@ RawFormat::set_bit_depth (int bits)
m_bit_depth = bits;
}
void
RawFormat::set_endian (Endian endian)
{
m_endian = endian;
}
RawInputStream::~RawInputStream()
{
close();
......
......@@ -10,9 +10,16 @@
class RawFormat
{
int m_n_channels = 0;
int m_sample_rate = 0;
int m_bit_depth = 0;
public:
enum Endian {
LITTLE,
BIG
};
private:
int m_n_channels = 0;
int m_sample_rate = 0;
int m_bit_depth = 0;
Endian m_endian = LITTLE;
public:
RawFormat();
RawFormat (int n_channels, int sample_rate, int bit_depth);
......@@ -20,10 +27,12 @@ public:
int n_channels() const { return m_n_channels; }
int sample_rate() const { return m_sample_rate; }
int bit_depth() const { return m_bit_depth; }
Endian endian() const { return m_endian; }
void set_channels (int channels);
void set_sample_rate (int rate);
void set_bit_depth (int bits);
void set_endian (Endian endian);
};
class RawConverter;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment