Skip to content

Consider template based design #1

Description

There are several common ways to store samples:

  • Unsigned 8-bit int
  • Signed 16-bit int
  • Signed 24 bit int
  • Signed 32 bit int
  • 32 bit float
  • 64 bit float

So the natural way to handle audio is templates based on storage type. In fact, in my own library I have 2 fundamental concepts:

template <typename T>
concept bool StorageType()
{
	return requires()
	{
		typename T::ValueType;
		{T::ValueSize} -> std::size_t;
		{T::BitDepth} -> std::size_t;
		{T::DefaultValue} -> typename T::ValueType;
		{T::MinimumValue()} -> typename T::ValueType;
		{T::MaximumValue()} -> typename T::ValueType;
		{T::ShouldClamp()} -> bool;
	};
}

template <typename T>
concept bool CalculationType()
{
	return General::Arithmetic<T>() && requires(double a)
	{
		T(a);
	};
}

The idea is that integer processing requires saturation arithmetic, int24 have special limits, floats are usually in [-1, 1] and do no need saturation arithmetic.

I'd say the design of StorageType can be made easier by introducing a dedicated type for saturation arithmetic - consider std::saturated<std::int16_t> - but that would hurt compatibility with C API that return std::intN_t because that would require conversion.

The idea that DSP code converts storage type to calculation type, performs arithmetic and converts back. Calculation type must be constructible from double so I can use constants in generic code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions