Commit 1172bb19 authored by Stefan Westerfeld's avatar Stefan Westerfeld

Support raw stream encoding (signed/unsigned).

Signed-off-by: Stefan Westerfeld's avatarStefan Westerfeld <stefan@space.twc.de>
parent 7b74c2cc
......@@ -160,6 +160,17 @@ parse_endian (const string& str)
exit (1);
}
RawFormat::Encoding
parse_encoding (const string& str)
{
if (str == "signed")
return RawFormat::Encoding::SIGNED;
if (str == "unsigned")
return RawFormat::Encoding::UNSIGNED;
error ("audiowmark: unsupported encoding '%s'\n", str.c_str());
exit (1);
}
void
parse_options (int *argc_p,
char **argv_p[])
......@@ -268,6 +279,22 @@ parse_options (int *argc_p,
Params::raw_input_format.set_endian (e);
Params::raw_output_format.set_endian (e);
}
else if (check_arg (argc, argv, &i, "--raw-input-encoding", &opt_arg))
{
auto e = parse_encoding (opt_arg);
Params::raw_input_format.set_encoding (e);
}
else if (check_arg (argc, argv, &i, "--raw-output-encoding", &opt_arg))
{
auto e = parse_encoding (opt_arg);
Params::raw_output_format.set_encoding (e);
}
else if (check_arg (argc, argv, &i, "--raw-encoding", &opt_arg))
{
auto e = parse_encoding (opt_arg);
Params::raw_input_format.set_encoding (e);
Params::raw_output_format.set_encoding (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, RawFormat::Endian ENDIAN>
template<int BIT_DEPTH, RawFormat::Endian ENDIAN, RawFormat::Encoding ENCODING>
class RawConverterImpl : public RawConverter
{
public:
......@@ -12,14 +12,27 @@ public:
void from_raw (const std::vector<unsigned char>& bytes, std::vector<float>& samples);
};
template<int BIT_DEPTH, RawFormat::Endian ENDIAN>
static RawConverter *
create_with_bits_endian (const RawFormat& raw_format, Error& error)
{
switch (raw_format.encoding())
{
case RawFormat::SIGNED: return new RawConverterImpl<BIT_DEPTH, ENDIAN, RawFormat::SIGNED>();
case RawFormat::UNSIGNED: return new RawConverterImpl<BIT_DEPTH, ENDIAN, RawFormat::UNSIGNED>();
}
error = Error ("unsupported encoding");
return nullptr;
}
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>();
case RawFormat::LITTLE: return create_with_bits_endian <BIT_DEPTH, RawFormat::LITTLE> (raw_format, error);
case RawFormat::BIG: return create_with_bits_endian <BIT_DEPTH, RawFormat::BIG> (raw_format, error);
}
error = Error ("unsupported endianness");
return nullptr;
......@@ -58,12 +71,13 @@ make_endian_shift ()
}
}
template<int BIT_DEPTH, RawFormat::Endian ENDIAN>
template<int BIT_DEPTH, RawFormat::Endian ENDIAN, RawFormat::Encoding ENCODING>
void
RawConverterImpl<BIT_DEPTH, ENDIAN>::to_raw (const vector<float>& samples, vector<unsigned char>& output_bytes)
RawConverterImpl<BIT_DEPTH, ENDIAN, ENCODING>::to_raw (const vector<float>& samples, vector<unsigned char>& output_bytes)
{
constexpr int sample_width = BIT_DEPTH / 8;
constexpr auto eshift = make_endian_shift<BIT_DEPTH, ENDIAN>();
constexpr unsigned char sign_flip = ENCODING == RawFormat::SIGNED ? 0x00 : 0x80;
output_bytes.resize (sample_width * samples.size());
......@@ -78,7 +92,7 @@ RawConverterImpl<BIT_DEPTH, ENDIAN>::to_raw (const vector<float>& samples, vecto
const int sample = lrint (bound<double> (min_value, samples[i] * norm, max_value));
if (eshift[0] >= 0)
ptr[0] = sample >> eshift[0];
ptr[0] = (sample >> eshift[0]) ^ sign_flip;
if (eshift[1] >= 0)
ptr[1] = sample >> eshift[1];
if (eshift[2] >= 0)
......@@ -88,13 +102,14 @@ RawConverterImpl<BIT_DEPTH, ENDIAN>::to_raw (const vector<float>& samples, vecto
}
}
template<int BIT_DEPTH, RawFormat::Endian ENDIAN>
template<int BIT_DEPTH, RawFormat::Endian ENDIAN, RawFormat::Encoding ENCODING>
void
RawConverterImpl<BIT_DEPTH, ENDIAN>::from_raw (const vector<unsigned char>& input_bytes, vector<float>& samples)
RawConverterImpl<BIT_DEPTH, ENDIAN, ENCODING>::from_raw (const vector<unsigned char>& input_bytes, vector<float>& samples)
{
const unsigned char *ptr = input_bytes.data();
constexpr int sample_width = BIT_DEPTH / 8;
constexpr auto eshift = make_endian_shift<BIT_DEPTH, ENDIAN>();
constexpr unsigned char sign_flip = ENCODING == RawFormat::SIGNED ? 0x00 : 0x80;
samples.resize (input_bytes.size() / sample_width);
const double norm = 1.0 / 0x80000000LL;
......@@ -103,7 +118,7 @@ RawConverterImpl<BIT_DEPTH, ENDIAN>::from_raw (const vector<unsigned char>& inpu
int s32 = 0;
if (eshift[0] >= 0)
s32 += ptr[0] << eshift[0];
s32 += (ptr[0] ^ sign_flip) << eshift[0];
if (eshift[1] >= 0)
s32 += ptr[1] << eshift[1];
if (eshift[2] >= 0)
......
......@@ -42,6 +42,12 @@ RawFormat::set_endian (Endian endian)
m_endian = endian;
}
void
RawFormat::set_encoding (Encoding encoding)
{
m_encoding = encoding;
}
RawInputStream::~RawInputStream()
{
close();
......
......@@ -15,11 +15,16 @@ public:
LITTLE,
BIG
};
enum Encoding {
SIGNED,
UNSIGNED
};
private:
int m_n_channels = 0;
int m_sample_rate = 0;
int m_bit_depth = 0;
Endian m_endian = LITTLE;
int m_n_channels = 0;
int m_sample_rate = 0;
int m_bit_depth = 0;
Endian m_endian = LITTLE;
Encoding m_encoding = SIGNED;
public:
RawFormat();
RawFormat (int n_channels, int sample_rate, int bit_depth);
......@@ -28,11 +33,13 @@ public:
int sample_rate() const { return m_sample_rate; }
int bit_depth() const { return m_bit_depth; }
Endian endian() const { return m_endian; }
Encoding encoding() const { return m_encoding; }
void set_channels (int channels);
void set_sample_rate (int rate);
void set_bit_depth (int bits);
void set_endian (Endian endian);
void set_encoding (Encoding encoding);
};
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