Skip to content

Consider template based design #1

@ghost

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions