Skip to content

Commit

Permalink
roc-streaminggh-608: Allow PCM mapping only between raw and non-raw
Browse files Browse the repository at this point in the history
This commit removes support for direct PCM mapping between
non-raw formats (e.g. int16 <=> int32). Now it's only allowed
to map from raw to non-raw, or vice versa, where "raw" format
is native-endian 32-bit floats.

This change significantly reduces code size (on x86_64/release
.o file is reduced from 5 MB to 80 KB), as well as simplifies
code generator script.

We did not actually use mapping between non-raw formats, except
tests, so the code is mostly unaffected. If we'll need that,
we can create a pair of mappers, first to map input format to
raw format, then to map raw format to output format.

Tests and comments are reworked as well.
  • Loading branch information
gavv committed Jul 6, 2024
1 parent 97e9090 commit 325b7df
Show file tree
Hide file tree
Showing 33 changed files with 2,733 additions and 11,694 deletions.
10,728 changes: 983 additions & 9,745 deletions src/internal_modules/roc_audio/pcm_format.cpp

Large diffs are not rendered by default.

281 changes: 161 additions & 120 deletions src/internal_modules/roc_audio/pcm_format_gen.py

Large diffs are not rendered by default.

23 changes: 14 additions & 9 deletions src/internal_modules/roc_audio/pcm_mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

#include "roc_audio/pcm_mapper.h"
#include "roc_audio/sample.h"
#include "roc_core/panic.h"
#include "roc_core/stddefs.h"

Expand All @@ -17,15 +18,19 @@ PcmMapper::PcmMapper(PcmFormat input_fmt, PcmFormat output_fmt)
: input_fmt_(input_fmt)
, output_fmt_(output_fmt)
, input_traits_(pcm_format_traits(input_fmt))
, output_traits_(pcm_format_traits(output_fmt))
, map_func_(pcm_format_mapfn(input_fmt, output_fmt)) {
if (!input_traits_.is_valid) {
roc_panic("pcm mapper: input format is not a pcm format");
}
if (!output_traits_.is_valid) {
roc_panic("pcm mapper: output format is not a pcm format");
}
if (!map_func_) {
, output_traits_(pcm_format_traits(output_fmt)) {
roc_panic_if_msg(!input_traits_.is_valid,
"pcm mapper: input format is not a pcm format");
roc_panic_if_msg(!output_traits_.is_valid,
"pcm mapper: output format is not a pcm format");

// To reduce code size, we generate converter only between raw and non-raw formats.
// To convert between two non-raw formats, you need a pair of pcm mappers.
roc_panic_if_msg(input_fmt != Sample_RawFormat && output_fmt != Sample_RawFormat,
"pcm mapper: either input or output format must be raw");

// This must not happen if checks above passed.
if (!(map_func_ = pcm_format_mapfn(input_fmt, output_fmt))) {
roc_panic("pcm mapper: unable to select mapping function");
}
}
Expand Down
23 changes: 12 additions & 11 deletions src/internal_modules/roc_audio/pcm_mapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ namespace roc {
namespace audio {

//! PCM format mapper.
//! Convert between PCM formats.
//! Converts between two PCM formats.
//! Either input or output format must be raw samples (Sample_RawFormat).
class PcmMapper : public core::NonCopyable<> {
public:
//! Initialize.
//! @pre
//! @p input_fmt and @p output_fmt should be PCM formats.
PcmMapper(PcmFormat input_fmt, PcmFormat output_fmt);

//! Get input format.
Expand All @@ -34,22 +33,22 @@ class PcmMapper : public core::NonCopyable<> {
//! Get output format.
PcmFormat output_format() const;

//! Get number of input samples per channel for given number of bytes.
//! Get number of input samples (total for all channels) for given number of bytes.
size_t input_sample_count(size_t input_bytes) const;

//! Get number of input samples per channel for given number of bytes.
//! Get number of input samples (total for all channels) for given number of bytes.
size_t output_sample_count(size_t output_bytes) const;

//! Get number of input bytes for given number of samples per channel.
//! Get number of input bytes for given number of samples (total for all channels).
size_t input_byte_count(size_t input_samples) const;

//! Get number of output bytes for given number of samples per channel.
//! Get number of output bytes for given number of samples (total for all channels).
size_t output_byte_count(size_t output_samples) const;

//! Get number of input bits for given number of samples per channel.
//! Get number of input bits for given number of samples (total for all channels).
size_t input_bit_count(size_t input_samples) const;

//! Get number of output bits for given number of samples per channel.
//! Get number of output bits for given number of samples (total for all channels).
size_t output_bit_count(size_t output_samples) const;

//! Map samples from input to output format.
Expand All @@ -60,12 +59,14 @@ class PcmMapper : public core::NonCopyable<> {
//! @p out_data is a pointer to output buffer
//! @p out_byte_size is size of output buffer in bytes
//! @p out_bit_off is an offset in output buffer in bits
//! @p n_samples is number of input and output samples for all channels
//! @p n_samples is number of input and output samples
//! (total for all channels) to be mapped
//! @returns
//! number of samples actually mapped, which may be truncated if
//! input or output buffer is smaller than requested
//! @note
//! updates @p in_bit_off and @p out_bit_off
//! increments @p in_bit_off and @p out_bit_off by the number
//! of mapped bits
size_t map(const void* in_data,
size_t in_byte_size,
size_t& in_bit_off,
Expand Down
22 changes: 15 additions & 7 deletions src/internal_modules/roc_audio/pcm_mapper_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ PcmMapperReader::PcmMapperReader(IFrameReader& frame_reader,
const SampleSpec& out_spec)
: frame_factory_(frame_factory)
, frame_reader_(frame_reader)
, mapper_(in_spec.pcm_format(), out_spec.pcm_format())
, in_spec_(in_spec)
, out_spec_(out_spec)
, num_ch_(out_spec.num_channels())
Expand All @@ -35,15 +34,24 @@ PcmMapperReader::PcmMapperReader(IFrameReader& frame_reader,
sample_spec_to_str(out_spec_).c_str());
}

if (!in_spec_.is_raw() && !out_spec_.is_raw()) {
roc_panic(
"pcm mapper reader: required either input our output spec to have raw format:"
" in_spec=%s out_spec=%s",
sample_spec_to_str(in_spec_).c_str(), sample_spec_to_str(out_spec_).c_str());
}

if (in_spec_.sample_rate() != out_spec_.sample_rate()
|| in_spec_.channel_set() != out_spec_.channel_set()) {
roc_panic(
"pcm mapper reader: required identical input and output rates and channels:"
" in_spec=%s out_spec=%s",
sample_spec_to_str(in_spec).c_str(), sample_spec_to_str(out_spec).c_str());
sample_spec_to_str(in_spec_).c_str(), sample_spec_to_str(out_spec_).c_str());
}

if (mapper_.input_bit_count(1) % 8 != 0 || mapper_.output_bit_count(1) % 8 != 0) {
mapper_.reset(new (mapper_) PcmMapper(in_spec_.pcm_format(), out_spec_.pcm_format()));

if (mapper_->input_bit_count(1) % 8 != 0 || mapper_->output_bit_count(1) % 8 != 0) {
roc_panic("pcm mapper reader: unsupported not byte-aligned encoding:"
" in_spec=%s out_spec=%s",
sample_spec_to_str(in_spec_).c_str(),
Expand Down Expand Up @@ -98,14 +106,14 @@ status::StatusCode PcmMapperReader::read(Frame& out_frame,
out_frame.set_duration(resulted_duration);
out_frame.set_capture_timestamp(in_frame_->capture_timestamp());

const size_t out_byte_count = mapper_.output_byte_count(resulted_duration * num_ch_);
const size_t out_byte_count = mapper_->output_byte_count(resulted_duration * num_ch_);
size_t out_bit_offset = 0;

const size_t in_byte_count = mapper_.input_byte_count(resulted_duration * num_ch_);
const size_t in_byte_count = mapper_->input_byte_count(resulted_duration * num_ch_);
size_t in_bit_offset = 0;

mapper_.map(in_frame_->bytes(), in_byte_count, in_bit_offset, out_frame.bytes(),
out_byte_count, out_bit_offset, resulted_duration * num_ch_);
mapper_->map(in_frame_->bytes(), in_byte_count, in_bit_offset, out_frame.bytes(),
out_byte_count, out_bit_offset, resulted_duration * num_ch_);

roc_panic_if(out_bit_offset != out_byte_count * 8);
roc_panic_if(in_bit_offset != in_byte_count * 8);
Expand Down
15 changes: 8 additions & 7 deletions src/internal_modules/roc_audio/pcm_mapper_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

//! @file roc_audio/pcm_mapper_reader.h
//! @brief Pcm mapper reader.
//! @brief PCM mapper reader.

#ifndef ROC_AUDIO_PCM_MAPPER_READER_H_
#define ROC_AUDIO_PCM_MAPPER_READER_H_
Expand All @@ -17,16 +17,17 @@
#include "roc_audio/pcm_mapper.h"
#include "roc_audio/sample_spec.h"
#include "roc_core/noncopyable.h"
#include "roc_core/slice.h"
#include "roc_core/stddefs.h"
#include "roc_core/time.h"
#include "roc_core/optional.h"
#include "roc_status/status_code.h"

namespace roc {
namespace audio {

//! Pcm mapper reader.
//! Reads frames from nested reader and maps them to another pcm mask.
//! PCM mapper reader.
//! Reads frames from nested reader and maps them to another PCM format.
//! @remarks
//! - Either input or output format must be raw samples (Sample_RawFormat).
//! - Both input and output formats must be byte-aligned.
class PcmMapperReader : public IFrameReader, public core::NonCopyable<> {
public:
//! Initialize.
Expand All @@ -48,7 +49,7 @@ class PcmMapperReader : public IFrameReader, public core::NonCopyable<> {

FramePtr in_frame_;

PcmMapper mapper_;
core::Optional<PcmMapper> mapper_;

const SampleSpec in_spec_;
const SampleSpec out_spec_;
Expand Down
24 changes: 16 additions & 8 deletions src/internal_modules/roc_audio/pcm_mapper_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ PcmMapperWriter::PcmMapperWriter(IFrameWriter& frame_writer,
const SampleSpec& out_spec)
: frame_factory_(frame_factory)
, frame_writer_(frame_writer)
, mapper_(in_spec.pcm_format(), out_spec.pcm_format())
, in_spec_(in_spec)
, out_spec_(out_spec)
, num_ch_(out_spec.num_channels())
Expand All @@ -40,10 +39,19 @@ PcmMapperWriter::PcmMapperWriter(IFrameWriter& frame_writer,
roc_panic(
"pcm mapper writer: required identical input and output rates and channels:"
" in_spec=%s out_spec=%s",
sample_spec_to_str(in_spec).c_str(), sample_spec_to_str(out_spec).c_str());
sample_spec_to_str(in_spec_).c_str(), sample_spec_to_str(out_spec_).c_str());
}

if (mapper_.input_bit_count(1) % 8 != 0 || mapper_.output_bit_count(1) % 8 != 0) {
if (!in_spec_.is_raw() && !out_spec_.is_raw()) {
roc_panic(
"pcm mapper writer: required either input our output spec to have raw format:"
" in_spec=%s out_spec=%s",
sample_spec_to_str(in_spec_).c_str(), sample_spec_to_str(out_spec_).c_str());
}

mapper_.reset(new (mapper_) PcmMapper(in_spec_.pcm_format(), out_spec_.pcm_format()));

if (mapper_->input_bit_count(1) % 8 != 0 || mapper_->output_bit_count(1) % 8 != 0) {
roc_panic("pcm mapper writer: unsupported not byte-aligned encoding:"
" in_spec=%s out_spec=%s",
sample_spec_to_str(in_spec_).c_str(),
Expand Down Expand Up @@ -93,15 +101,15 @@ status::StatusCode PcmMapperWriter::write(Frame& in_frame) {
}

const size_t out_byte_count =
mapper_.output_byte_count(capped_duration * num_ch_);
mapper_->output_byte_count(capped_duration * num_ch_);
size_t out_bit_offset = 0;

const size_t in_byte_count = mapper_.input_byte_count(capped_duration * num_ch_);
const size_t in_byte_count = mapper_->input_byte_count(capped_duration * num_ch_);
size_t in_bit_offset = 0;

mapper_.map(in_frame.bytes() + in_pos, in_byte_count, in_bit_offset,
out_frame_->bytes(), out_byte_count, out_bit_offset,
capped_duration * num_ch_);
mapper_->map(in_frame.bytes() + in_pos, in_byte_count, in_bit_offset,
out_frame_->bytes(), out_byte_count, out_bit_offset,
capped_duration * num_ch_);

roc_panic_if(out_bit_offset != out_byte_count * 8);
roc_panic_if(in_bit_offset != in_byte_count * 8);
Expand Down
15 changes: 8 additions & 7 deletions src/internal_modules/roc_audio/pcm_mapper_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

//! @file roc_audio/pcm_mapper_writer.h
//! @brief Pcm mapper writer.
//! @brief PCM mapper writer.

#ifndef ROC_AUDIO_PCM_MAPPER_WRITER_H_
#define ROC_AUDIO_PCM_MAPPER_WRITER_H_
Expand All @@ -17,16 +17,17 @@
#include "roc_audio/pcm_mapper.h"
#include "roc_audio/sample_spec.h"
#include "roc_core/noncopyable.h"
#include "roc_core/slice.h"
#include "roc_core/stddefs.h"
#include "roc_core/time.h"
#include "roc_core/optional.h"
#include "roc_status/status_code.h"

namespace roc {
namespace audio {

//! Pcm mapper writer.
//! Reads frames from nested writer and maps them to another pcm mask.
//! PCM mapper writer.
//! Maps frames to another PCM format and writes them to nested writer.
//! @remarks
//! - Either input or output format must be raw samples (Sample_RawFormat).
//! - Both input and output formats must be byte-aligned.
class PcmMapperWriter : public IFrameWriter, public core::NonCopyable<> {
public:
//! Initialize.
Expand All @@ -47,7 +48,7 @@ class PcmMapperWriter : public IFrameWriter, public core::NonCopyable<> {

FramePtr out_frame_;

PcmMapper mapper_;
core::Optional<PcmMapper> mapper_;

const SampleSpec in_spec_;
const SampleSpec out_spec_;
Expand Down
2 changes: 1 addition & 1 deletion src/internal_modules/roc_core/print_memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ void print_number_t(Printer& p, int64_t v) {
}

void print_number_t(Printer& p, float v) {
p.writef("%.4f", (double)v);
p.writef("%.6f", (double)v);
}

void print_number_t(Printer& p, double v) {
Expand Down
Loading

0 comments on commit 325b7df

Please sign in to comment.