11#include <promeki/config.h>
12#if PROMEKI_ENABLE_PROAV
26PROMEKI_NAMESPACE_BEGIN
95 PROMEKI_DATATYPE(AudioFormat, DataTypeAudioFormat, 1)
98 Error writeToStream(DataStream &s) const;
100 template <uint32_t V> static Result<AudioFormat> readFromStream(DataStream &s);
103 static constexpr int32_t MinS24 = -8388608;
105 static constexpr int32_t MaxS24 = 8388607;
107 static constexpr int32_t MinU24 = 0;
109 static constexpr int32_t MaxU24 = 16777215;
143 PCMI_S24LE_HB32 = 17,
144 PCMI_S24LE_LB32 = 18,
145 PCMI_S24BE_HB32 = 19,
146 PCMI_S24BE_LB32 = 20,
147 PCMI_U24LE_HB32 = 21,
148 PCMI_U24LE_LB32 = 22,
149 PCMI_U24BE_HB32 = 23,
150 PCMI_U24BE_LB32 = 24,
171 PCMP_S24LE_HB32 = 48,
172 PCMP_S24LE_LB32 = 49,
173 PCMP_S24BE_HB32 = 50,
174 PCMP_S24BE_LB32 = 51,
175 PCMP_U24LE_HB32 = 52,
176 PCMP_U24LE_LB32 = 53,
177 PCMP_U24BE_HB32 = 54,
178 PCMP_U24BE_LB32 = 55,
191 using IDList = ::promeki::List<ID>;
200 static constexpr ID NativeFloat = System::isLittleEndian() ? PCMI_Float32LE : PCMI_Float32BE;
217 size_t bytesPerSample = 0;
218 size_t bitsPerSample = 0;
219 bool isSigned =
false;
220 bool isFloat =
false;
221 bool isPlanar =
false;
222 bool isBigEndian =
false;
223 bool compressed =
false;
224 AudioCodec audioCodec;
225 FourCC::List fourccList;
232 void (*samplesToFloat)(
float *out,
const uint8_t *in,
size_t samples) =
nullptr;
239 void (*floatToSamples)(uint8_t *out,
const float *in,
size_t samples) =
nullptr;
247 static ID registerType();
259 static void registerData(Data &&data);
265 static IDList registeredIDs();
274 static Result<AudioFormat> lookup(
const String &name);
284 static Result<AudioFormat> fromString(
const String &name);
298 static AudioFormat lookupByFourCC(
const FourCC &fcc);
304 inline AudioFormat(ID
id = Invalid);
307 bool isValid()
const {
return d !=
nullptr && d->id != Invalid; }
310 ID id()
const {
return d->id; }
313 const String &name()
const {
return d->name; }
316 const String &desc()
const {
return d->desc; }
319 size_t bytesPerSample()
const {
return d->bytesPerSample; }
322 size_t bitsPerSample()
const {
return d->bitsPerSample; }
325 bool isSigned()
const {
return d->isSigned; }
328 bool isFloat()
const {
return d->isFloat; }
331 bool isPlanar()
const {
return d->isPlanar; }
334 bool isBigEndian()
const {
return d->isBigEndian; }
337 bool isCompressed()
const {
return d->compressed; }
346 const AudioCodec &audioCodec()
const {
return d->audioCodec; }
349 const FourCC::List &fourccList()
const {
return d->fourccList; }
358 void samplesToFloat(
float *out,
const uint8_t *in,
size_t samples)
const {
359 if (d->samplesToFloat !=
nullptr) d->samplesToFloat(out, in, samples);
368 void floatToSamples(uint8_t *out,
const float *in,
size_t samples)
const {
369 if (d->floatToSamples !=
nullptr) d->floatToSamples(out, in, samples);
390 using DirectConvertFn = void (*)(
void *out,
const void *in,
size_t samples);
398 static DirectConvertFn directConverter(ID src, ID dst);
414 static bool isBitAccurate(ID src, ID dst);
429 static void registerDirectConverter(ID src, ID dst, DirectConvertFn fn,
bool bitAccurate);
432 bool hasDirectConverterTo(
const AudioFormat &dst)
const {
433 return directConverter(
id(), dst.id()) !=
nullptr;
437 bool isBitAccurateTo(
const AudioFormat &dst)
const {
return isBitAccurate(
id(), dst.id()); }
466 Error convertTo(
const AudioFormat &dst,
void *out,
const void *in,
size_t samples,
467 float *scratch =
nullptr)
const;
500 Error convertTo(
const AudioFormat &dst,
void *out,
const void *in,
size_t samplesPerChannel,
501 size_t channels,
float *scratch =
nullptr)
const;
504 bool operator==(
const AudioFormat &o)
const {
return d == o.d; }
507 bool operator!=(
const AudioFormat &o)
const {
return d != o.d; }
510 const String &toString()
const {
return d->name; }
513 const Data *data()
const {
return d; }
538 template <
typename IntegerType, IntegerType Min, IntegerType Max>
539 static float integerToFloat(IntegerType value) {
540 static_assert(std::is_integral<IntegerType>::value,
"IntegerType must be an integer.");
541 if constexpr (Min < 0) {
549 constexpr float scaleNeg = -
static_cast<float>(Min);
550 constexpr float scalePos =
static_cast<float>(Max);
551 constexpr float scale = scaleNeg > scalePos ? scaleNeg : scalePos;
552 return static_cast<float>(value) / scale;
554 constexpr float min =
static_cast<float>(Min);
555 constexpr float max =
static_cast<float>(Max);
556 return ((
static_cast<float>(value) - min) * 2.0f / (max - min)) - 1.0f;
566 template <
typename IntegerType>
static float integerToFloat(IntegerType value) {
567 static_assert(std::is_integral<IntegerType>::value,
"IntegerType must be an integer.");
568 return integerToFloat<IntegerType, std::numeric_limits<IntegerType>::min(),
569 std::numeric_limits<IntegerType>::max()>(value);
590 template <
typename IntegerType, IntegerType Min, IntegerType Max>
591 static IntegerType floatToInteger(
float value) {
592 static_assert(std::is_integral<IntegerType>::value,
"IntegerType must be an integer.");
593 if (value <= -1.0f)
return Min;
594 if (value >= 1.0f)
return Max;
595 if constexpr (Min < 0) {
599 constexpr float scaleNeg = -
static_cast<float>(Min);
600 constexpr float scalePos =
static_cast<float>(Max);
601 constexpr float scale = scaleNeg > scalePos ? scaleNeg : scalePos;
602 return static_cast<IntegerType
>(value * scale);
604 const float min =
static_cast<float>(Min);
605 const float max =
static_cast<float>(Max);
606 return static_cast<IntegerType
>((value + 1.0f) * 0.5f * (max - min) + min);
616 template <
typename IntegerType>
static IntegerType floatToInteger(
float value) {
617 static_assert(std::is_integral<IntegerType>::value,
"IntegerType must be an integer.");
618 return floatToInteger<IntegerType, std::numeric_limits<IntegerType>::min(),
619 std::numeric_limits<IntegerType>::max()>(value);
634 template <
typename IntegerType,
bool InputIsBigEndian>
635 static void samplesToFloatImpl(
float *out,
const uint8_t *inbuf,
size_t samples) {
636 static_assert(std::is_integral<IntegerType>::value,
"IntegerType must be an integer.");
637 const IntegerType *in =
reinterpret_cast<const IntegerType *
>(inbuf);
638 for (
size_t i = 0; i < samples; ++i) {
639 IntegerType val = *in++;
640 if constexpr (InputIsBigEndian != System::isBigEndian()) System::swapEndian(val);
641 *out++ = integerToFloat<IntegerType>(val);
657 template <
typename IntegerType,
bool OutputIsBigEndian>
658 static void floatToSamplesImpl(uint8_t *outbuf,
const float *in,
size_t samples) {
659 static_assert(std::is_integral<IntegerType>::value,
"IntegerType must be an integer.");
660 IntegerType *out =
reinterpret_cast<IntegerType *
>(outbuf);
661 for (
size_t i = 0; i < samples; ++i) {
662 IntegerType val = floatToInteger<IntegerType>(*in++);
663 if constexpr (OutputIsBigEndian != System::isBigEndian()) System::swapEndian(val);
669 const Data *d =
nullptr;
670 static const Data *lookupData(ID
id);
673inline AudioFormat::AudioFormat(ID
id) : d(lookupData(id)) {}