pcm/*: use std::span instead of ConstBuffer
This commit is contained in:
parent
d89136b09c
commit
4ce1dae673
@ -511,9 +511,9 @@ DecoderBridge::SubmitData(InputStream *is,
|
|||||||
assert(dc.in_audio_format != dc.out_audio_format);
|
assert(dc.in_audio_format != dc.out_audio_format);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto result = convert->Convert({data, length});
|
auto result = convert->Convert({(const std::byte *)data, length});
|
||||||
data = result.data;
|
data = result.data();
|
||||||
length = result.size;
|
length = result.size();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
/* the PCM conversion has failed - stop
|
/* the PCM conversion has failed - stop
|
||||||
playback, since we have no better way to
|
playback, since we have no better way to
|
||||||
|
@ -227,8 +227,7 @@ VorbisDecoder::SubmitSomePcm()
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
PcmInterleaveFloat(buffer,
|
PcmInterleaveFloat(buffer,
|
||||||
ConstBuffer<const in_sample_t *>(pcm,
|
{pcm, channels},
|
||||||
channels),
|
|
||||||
n_frames);
|
n_frames);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ public:
|
|||||||
ConstBuffer<void> Flush() override {
|
ConstBuffer<void> Flush() override {
|
||||||
return state
|
return state
|
||||||
? state->Flush()
|
? state->Flush()
|
||||||
: nullptr;
|
: std::span<const std::byte>{};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ ConvertFilter::FilterPCM(ConstBuffer<void> src)
|
|||||||
return state
|
return state
|
||||||
? state->Convert(src)
|
? state->Convert(src)
|
||||||
/* optimized special case: no-op */
|
/* optimized special case: no-op */
|
||||||
: src;
|
: std::span<const std::byte>{src};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<PreparedFilter>
|
std::unique_ptr<PreparedFilter>
|
||||||
|
@ -201,7 +201,7 @@ ConstBuffer<void>
|
|||||||
ReplayGainFilter::FilterPCM(ConstBuffer<void> src)
|
ReplayGainFilter::FilterPCM(ConstBuffer<void> src)
|
||||||
{
|
{
|
||||||
return mixer != nullptr
|
return mixer != nullptr
|
||||||
? src
|
? std::span<const std::byte>{src}
|
||||||
: pv.Apply(src);
|
: pv.Apply(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,8 +57,7 @@ InterleaveFrame(const AVFrame &frame, FfmpegBuffer &buffer)
|
|||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
|
|
||||||
PcmInterleave(output_buffer,
|
PcmInterleave(output_buffer,
|
||||||
ConstBuffer<const void *>((const void *const*)frame.extended_data,
|
{(const void *const*)frame.extended_data, channels},
|
||||||
channels),
|
|
||||||
n_frames,
|
n_frames,
|
||||||
av_get_bytes_per_sample(format));
|
av_get_bytes_per_sample(format));
|
||||||
} else {
|
} else {
|
||||||
|
@ -1231,13 +1231,13 @@ AlsaOutput::Play(const void *chunk, size_t size)
|
|||||||
if (size > max_size)
|
if (size > max_size)
|
||||||
size = max_size;
|
size = max_size;
|
||||||
|
|
||||||
const auto e = pcm_export->Export({chunk, size});
|
const auto e = pcm_export->Export({(const std::byte *)chunk, size});
|
||||||
if (e.empty())
|
if (e.empty())
|
||||||
return size;
|
return size;
|
||||||
|
|
||||||
size_t bytes_written = ring_buffer->push((const uint8_t *)e.data,
|
size_t bytes_written = ring_buffer->push((const uint8_t *)e.data(),
|
||||||
e.size);
|
e.size());
|
||||||
assert(bytes_written == e.size);
|
assert(bytes_written == e.size());
|
||||||
(void)bytes_written;
|
(void)bytes_written;
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
|
@ -691,12 +691,12 @@ OssOutput::Play(const void *chunk, size_t size)
|
|||||||
if (!fd.IsDefined())
|
if (!fd.IsDefined())
|
||||||
Reopen();
|
Reopen();
|
||||||
|
|
||||||
const auto e = pcm_export->Export({chunk, size});
|
const auto e = pcm_export->Export({(const std::byte *)chunk, size});
|
||||||
if (e.empty())
|
if (e.empty())
|
||||||
return size;
|
return size;
|
||||||
|
|
||||||
chunk = e.data;
|
chunk = e.data();
|
||||||
size = e.size;
|
size = e.size();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
ret = fd.Write(chunk, size);
|
ret = fd.Write(chunk, size);
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
|
|
||||||
#include "ChannelsConverter.hxx"
|
#include "ChannelsConverter.hxx"
|
||||||
#include "PcmChannels.hxx"
|
#include "PcmChannels.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
|
#include "util/SpanCast.hxx"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
@ -55,8 +55,8 @@ PcmChannelsConverter::Close() noexcept
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
PcmChannelsConverter::Convert(ConstBuffer<void> src) noexcept
|
PcmChannelsConverter::Convert(std::span<const std::byte> src) noexcept
|
||||||
{
|
{
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case SampleFormat::UNDEFINED:
|
case SampleFormat::UNDEFINED:
|
||||||
@ -66,24 +66,24 @@ PcmChannelsConverter::Convert(ConstBuffer<void> src) noexcept
|
|||||||
gcc_unreachable();
|
gcc_unreachable();
|
||||||
|
|
||||||
case SampleFormat::S16:
|
case SampleFormat::S16:
|
||||||
return pcm_convert_channels_16(buffer, dest_channels,
|
return std::as_bytes(pcm_convert_channels_16(buffer, dest_channels,
|
||||||
src_channels,
|
src_channels,
|
||||||
ConstBuffer<int16_t>::FromVoid(src)).ToVoid();
|
FromBytesStrict<const int16_t>(src)));
|
||||||
|
|
||||||
case SampleFormat::S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
return pcm_convert_channels_24(buffer, dest_channels,
|
return std::as_bytes(pcm_convert_channels_24(buffer, dest_channels,
|
||||||
src_channels,
|
src_channels,
|
||||||
ConstBuffer<int32_t>::FromVoid(src)).ToVoid();
|
FromBytesStrict<const int32_t>(src)));
|
||||||
|
|
||||||
case SampleFormat::S32:
|
case SampleFormat::S32:
|
||||||
return pcm_convert_channels_32(buffer, dest_channels,
|
return std::as_bytes(pcm_convert_channels_32(buffer, dest_channels,
|
||||||
src_channels,
|
src_channels,
|
||||||
ConstBuffer<int32_t>::FromVoid(src)).ToVoid();
|
FromBytesStrict<const int32_t>(src)));
|
||||||
|
|
||||||
case SampleFormat::FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
return pcm_convert_channels_float(buffer, dest_channels,
|
return std::as_bytes(pcm_convert_channels_float(buffer, dest_channels,
|
||||||
src_channels,
|
src_channels,
|
||||||
ConstBuffer<float>::FromVoid(src)).ToVoid();
|
FromBytesStrict<const float>(src)));
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
|
@ -23,12 +23,12 @@
|
|||||||
#include "SampleFormat.hxx"
|
#include "SampleFormat.hxx"
|
||||||
#include "Buffer.hxx"
|
#include "Buffer.hxx"
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that converts samples from one format to another.
|
* A class that converts samples from one format to another.
|
||||||
*/
|
*/
|
||||||
@ -74,7 +74,7 @@ public:
|
|||||||
* @return the destination buffer
|
* @return the destination buffer
|
||||||
*/
|
*/
|
||||||
[[gnu::pure]]
|
[[gnu::pure]]
|
||||||
ConstBuffer<void> Convert(ConstBuffer<void> src) noexcept;
|
std::span<const std::byte> Convert(std::span<const std::byte> src) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "Convert.hxx"
|
#include "Convert.hxx"
|
||||||
#include "ConfiguredResampler.hxx"
|
#include "ConfiguredResampler.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
#include "util/SpanCast.hxx"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@ -111,16 +111,16 @@ PcmConvert::Reset() noexcept
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
PcmConvert::Convert(ConstBuffer<void> buffer)
|
PcmConvert::Convert(std::span<const std::byte> buffer)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
if (src_format.format == SampleFormat::DSD) {
|
if (src_format.format == SampleFormat::DSD) {
|
||||||
auto s = ConstBuffer<uint8_t>::FromVoid(buffer);
|
auto s = FromBytesStrict<const uint8_t>(buffer);
|
||||||
auto d = dsd2pcm_float
|
auto d = dsd2pcm_float
|
||||||
? dsd.ToFloat(src_format.channels, s).ToVoid()
|
? std::as_bytes(dsd.ToFloat(src_format.channels, s))
|
||||||
: dsd.ToS24(src_format.channels, s).ToVoid();
|
: std::as_bytes(dsd.ToS24(src_format.channels, s));
|
||||||
if (d.IsNull())
|
if (d.data() == nullptr)
|
||||||
throw std::runtime_error("DSD to PCM conversion failed");
|
throw std::runtime_error("DSD to PCM conversion failed");
|
||||||
|
|
||||||
buffer = d;
|
buffer = d;
|
||||||
@ -139,12 +139,12 @@ PcmConvert::Convert(ConstBuffer<void> buffer)
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
PcmConvert::Flush()
|
PcmConvert::Flush()
|
||||||
{
|
{
|
||||||
if (enable_resampler) {
|
if (enable_resampler) {
|
||||||
auto buffer = resampler.Flush();
|
auto buffer = resampler.Flush();
|
||||||
if (!buffer.IsNull()) {
|
if (buffer.data() != nullptr) {
|
||||||
if (enable_format)
|
if (enable_format)
|
||||||
buffer = format_converter.Convert(buffer);
|
buffer = format_converter.Convert(buffer);
|
||||||
|
|
||||||
@ -155,5 +155,5 @@ PcmConvert::Flush()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,9 @@
|
|||||||
#include "PcmDsd.hxx"
|
#include "PcmDsd.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename T> struct ConstBuffer;
|
#include <cstddef>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
struct ConfigData;
|
struct ConfigData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,13 +79,13 @@ public:
|
|||||||
* @param src the source PCM buffer
|
* @param src the source PCM buffer
|
||||||
* @return the destination buffer
|
* @return the destination buffer
|
||||||
*/
|
*/
|
||||||
ConstBuffer<void> Convert(ConstBuffer<void> src);
|
std::span<const std::byte> Convert(std::span<const std::byte> src);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush pending data and return it. This should be called
|
* Flush pending data and return it. This should be called
|
||||||
* repepatedly until it returns nullptr.
|
* repepatedly until it returns nullptr.
|
||||||
*/
|
*/
|
||||||
ConstBuffer<void> Flush();
|
std::span<const std::byte> Flush();
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "Dop.hxx"
|
#include "Dop.hxx"
|
||||||
#include "ChannelDefs.hxx"
|
#include "ChannelDefs.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -88,8 +87,8 @@ DsdToDopConverter::Open(unsigned _channels) noexcept
|
|||||||
rest_buffer.Open(channels);
|
rest_buffer.Open(channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<uint32_t>
|
std::span<const uint32_t>
|
||||||
DsdToDopConverter::Convert(ConstBuffer<uint8_t> src) noexcept
|
DsdToDopConverter::Convert(std::span<const uint8_t> src) noexcept
|
||||||
{
|
{
|
||||||
return rest_buffer.Process<uint32_t>(buffer, src, 2 * channels,
|
return rest_buffer.Process<uint32_t>(buffer, src, 2 * channels,
|
||||||
[this](auto && arg1, auto && arg2, auto && arg3) { return DsdToDop(arg1, arg2, arg3, channels); });
|
[this](auto && arg1, auto && arg2, auto && arg3) { return DsdToDop(arg1, arg2, arg3, channels); });
|
||||||
|
@ -24,8 +24,7 @@
|
|||||||
#include "RestBuffer.hxx"
|
#include "RestBuffer.hxx"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pack DSD 1 bit samples into (padded) 24 bit PCM samples for
|
* Pack DSD 1 bit samples into (padded) 24 bit PCM samples for
|
||||||
@ -60,7 +59,7 @@ public:
|
|||||||
return 2 * GetInputBlockSize();
|
return 2 * GetInputBlockSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<uint32_t> Convert(ConstBuffer<uint8_t> src) noexcept;
|
std::span<const uint32_t> Convert(std::span<const uint8_t> src) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,9 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Dsd16.hxx"
|
#include "Dsd16.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a 16 bit integer from two bytes.
|
* Construct a 16 bit integer from two bytes.
|
||||||
@ -60,8 +57,8 @@ Dsd16Converter::Open(unsigned _channels) noexcept
|
|||||||
rest_buffer.Open(channels);
|
rest_buffer.Open(channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<uint16_t>
|
std::span<const uint16_t>
|
||||||
Dsd16Converter::Convert(ConstBuffer<uint8_t> src) noexcept
|
Dsd16Converter::Convert(std::span<const uint8_t> src) noexcept
|
||||||
{
|
{
|
||||||
return rest_buffer.Process<uint16_t>(buffer, src, channels,
|
return rest_buffer.Process<uint16_t>(buffer, src, channels,
|
||||||
[this](auto && arg1, auto && arg2, auto && arg3) { return Dsd8To16(arg1, arg2, arg3, channels); });
|
[this](auto && arg1, auto && arg2, auto && arg3) { return Dsd8To16(arg1, arg2, arg3, channels); });
|
||||||
|
@ -24,8 +24,7 @@
|
|||||||
#include "RestBuffer.hxx"
|
#include "RestBuffer.hxx"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert DSD_U8 to DSD_U16 (native endian, oldest bits in MSB).
|
* Convert DSD_U8 to DSD_U16 (native endian, oldest bits in MSB).
|
||||||
@ -58,7 +57,7 @@ public:
|
|||||||
return GetInputBlockSize();
|
return GetInputBlockSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<uint16_t> Convert(ConstBuffer<uint8_t> src) noexcept;
|
std::span<const uint16_t> Convert(std::span<const uint8_t> src) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,9 +18,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Dsd32.hxx"
|
#include "Dsd32.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a 32 bit integer from four bytes.
|
* Construct a 32 bit integer from four bytes.
|
||||||
@ -62,8 +59,8 @@ Dsd32Converter::Open(unsigned _channels) noexcept
|
|||||||
rest_buffer.Open(channels);
|
rest_buffer.Open(channels);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<uint32_t>
|
std::span<const uint32_t>
|
||||||
Dsd32Converter::Convert(ConstBuffer<uint8_t> src) noexcept
|
Dsd32Converter::Convert(std::span<const uint8_t> src) noexcept
|
||||||
{
|
{
|
||||||
return rest_buffer.Process<uint32_t>(buffer, src, channels,
|
return rest_buffer.Process<uint32_t>(buffer, src, channels,
|
||||||
[this](auto && arg1, auto && arg2, auto && arg3) { return Dsd8To32(arg1, arg2, arg3, channels); });
|
[this](auto && arg1, auto && arg2, auto && arg3) { return Dsd8To32(arg1, arg2, arg3, channels); });
|
||||||
|
@ -24,8 +24,7 @@
|
|||||||
#include "RestBuffer.hxx"
|
#include "RestBuffer.hxx"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert DSD_U8 to DSD_U32 (native endian, oldest bits in MSB).
|
* Convert DSD_U8 to DSD_U32 (native endian, oldest bits in MSB).
|
||||||
@ -58,7 +57,7 @@ public:
|
|||||||
return GetInputBlockSize();
|
return GetInputBlockSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<uint32_t> Convert(ConstBuffer<uint8_t> src) noexcept;
|
std::span<const uint32_t> Convert(std::span<const uint8_t> src) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,12 +22,11 @@
|
|||||||
#include "Pack.hxx"
|
#include "Pack.hxx"
|
||||||
#include "Silence.hxx"
|
#include "Silence.hxx"
|
||||||
#include "util/ByteReverse.hxx"
|
#include "util/ByteReverse.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
#include "util/SpanCast.hxx"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
void
|
void
|
||||||
PcmExport::Open(SampleFormat sample_format, unsigned _channels,
|
PcmExport::Open(SampleFormat sample_format, unsigned _channels,
|
||||||
Params params) noexcept
|
Params params) noexcept
|
||||||
@ -98,9 +97,9 @@ PcmExport::Open(SampleFormat sample_format, unsigned _channels,
|
|||||||
assert(buffer_size < sizeof(buffer));
|
assert(buffer_size < sizeof(buffer));
|
||||||
PcmSilence({buffer, buffer_size}, src_sample_format);
|
PcmSilence({buffer, buffer_size}, src_sample_format);
|
||||||
auto s = Export({buffer, buffer_size});
|
auto s = Export({buffer, buffer_size});
|
||||||
assert(s.size < sizeof(silence_buffer));
|
assert(s.size() < sizeof(silence_buffer));
|
||||||
silence_size = s.size;
|
silence_size = s.size();
|
||||||
memcpy(silence_buffer, s.data, s.size);
|
std::copy(s.begin(), s.end(), silence_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -200,7 +199,7 @@ PcmExport::GetOutputBlockSize() const noexcept
|
|||||||
return GetOutputFrameSize();
|
return GetOutputFrameSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
PcmExport::GetSilence() const noexcept
|
PcmExport::GetSilence() const noexcept
|
||||||
{
|
{
|
||||||
return {silence_buffer, silence_size};
|
return {silence_buffer, silence_size};
|
||||||
@ -262,8 +261,8 @@ PcmExport::Params::CalcInputSampleRate(unsigned sample_rate) const noexcept
|
|||||||
return sample_rate;
|
return sample_rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
PcmExport::Export(ConstBuffer<void> data) noexcept
|
PcmExport::Export(std::span<const std::byte> data) noexcept
|
||||||
{
|
{
|
||||||
if (alsa_channel_order)
|
if (alsa_channel_order)
|
||||||
data = ToAlsaChannelOrder(order_buffer, data,
|
data = ToAlsaChannelOrder(order_buffer, data,
|
||||||
@ -275,38 +274,34 @@ PcmExport::Export(ConstBuffer<void> data) noexcept
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DsdMode::U16:
|
case DsdMode::U16:
|
||||||
data = dsd16_converter.Convert(ConstBuffer<uint8_t>::FromVoid(data))
|
data = std::as_bytes(dsd16_converter.Convert(FromBytesStrict<const uint8_t>(data)));
|
||||||
.ToVoid();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DsdMode::U32:
|
case DsdMode::U32:
|
||||||
data = dsd32_converter.Convert(ConstBuffer<uint8_t>::FromVoid(data))
|
data = std::as_bytes(dsd32_converter.Convert(FromBytesStrict<const uint8_t>(data)));
|
||||||
.ToVoid();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DsdMode::DOP:
|
case DsdMode::DOP:
|
||||||
data = dop_converter.Convert(ConstBuffer<uint8_t>::FromVoid(data))
|
data = std::as_bytes(dop_converter.Convert(FromBytesStrict<const uint8_t>(data)));
|
||||||
.ToVoid();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pack24) {
|
if (pack24) {
|
||||||
const auto src = ConstBuffer<int32_t>::FromVoid(data);
|
const auto src = FromBytesStrict<const int32_t>(data);
|
||||||
const size_t num_samples = src.size;
|
const size_t num_samples = src.size();
|
||||||
const size_t dest_size = num_samples * 3;
|
const size_t dest_size = num_samples * 3;
|
||||||
auto *dest = (uint8_t *)pack_buffer.Get(dest_size);
|
auto *dest = (uint8_t *)pack_buffer.Get(dest_size);
|
||||||
assert(dest != nullptr);
|
assert(dest != nullptr);
|
||||||
|
|
||||||
pcm_pack_24(dest, src.begin(), src.end());
|
pcm_pack_24(dest, src.data(), src.data() + src.size());
|
||||||
|
|
||||||
data.data = dest;
|
data = std::as_bytes(std::span{dest, dest_size});
|
||||||
data.size = dest_size;
|
|
||||||
} else if (shift8) {
|
} else if (shift8) {
|
||||||
const auto src = ConstBuffer<int32_t>::FromVoid(data);
|
const auto src = FromBytesStrict<const int32_t>(data);
|
||||||
|
|
||||||
auto *dest = (uint32_t *)pack_buffer.Get(data.size);
|
auto *dest = (uint32_t *)pack_buffer.Get(data.size());
|
||||||
data.data = dest;
|
data = {(const std::byte *)dest, data.size()};
|
||||||
|
|
||||||
for (auto i : src)
|
for (auto i : src)
|
||||||
*dest++ = i << 8;
|
*dest++ = i << 8;
|
||||||
@ -315,13 +310,14 @@ PcmExport::Export(ConstBuffer<void> data) noexcept
|
|||||||
if (reverse_endian > 0) {
|
if (reverse_endian > 0) {
|
||||||
assert(reverse_endian >= 2);
|
assert(reverse_endian >= 2);
|
||||||
|
|
||||||
const auto src = ConstBuffer<uint8_t>::FromVoid(data);
|
const auto src = FromBytesStrict<const uint8_t>(data);
|
||||||
|
|
||||||
auto *dest = (uint8_t *)reverse_buffer.Get(data.size);
|
auto *dest = (uint8_t *)reverse_buffer.Get(data.size());
|
||||||
assert(dest != nullptr);
|
assert(dest != nullptr);
|
||||||
data.data = dest;
|
data = {(const std::byte *)dest, data.size()};
|
||||||
|
|
||||||
reverse_bytes(dest, src.begin(), src.end(), reverse_endian);
|
reverse_bytes(dest, src.data(), src.data() + src.size(),
|
||||||
|
reverse_endian);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
@ -30,9 +30,9 @@
|
|||||||
#include "Dop.hxx"
|
#include "Dop.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object that handles export of PCM samples to some instance
|
* An object that handles export of PCM samples to some instance
|
||||||
@ -80,7 +80,7 @@ class PcmExport {
|
|||||||
|
|
||||||
size_t silence_size;
|
size_t silence_size;
|
||||||
|
|
||||||
uint8_t silence_buffer[64]; /* worst-case size */
|
std::byte silence_buffer[64]; /* worst-case size */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sample format of input data.
|
* The sample format of input data.
|
||||||
@ -227,7 +227,7 @@ public:
|
|||||||
* this #PcmExport object exists and until the next Open()
|
* this #PcmExport object exists and until the next Open()
|
||||||
* call
|
* call
|
||||||
*/
|
*/
|
||||||
ConstBuffer<void> GetSilence() const noexcept;
|
std::span<const std::byte> GetSilence() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export a PCM buffer.
|
* Export a PCM buffer.
|
||||||
@ -236,7 +236,7 @@ public:
|
|||||||
* @return the destination buffer; may be empty (and may be a
|
* @return the destination buffer; may be empty (and may be a
|
||||||
* pointer to the source buffer)
|
* pointer to the source buffer)
|
||||||
*/
|
*/
|
||||||
ConstBuffer<void> Export(ConstBuffer<void> src) noexcept;
|
std::span<const std::byte> Export(std::span<const std::byte> src) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the number of consumed bytes from the Export()
|
* Converts the number of consumed bytes from the Export()
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FallbackResampler.hxx"
|
#include "FallbackResampler.hxx"
|
||||||
|
#include "util/SpanCast.hxx"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
@ -61,22 +62,22 @@ FallbackPcmResampler::Close() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static ConstBuffer<T>
|
static std::span<const T>
|
||||||
pcm_resample_fallback(PcmBuffer &buffer,
|
pcm_resample_fallback(PcmBuffer &buffer,
|
||||||
unsigned channels,
|
unsigned channels,
|
||||||
unsigned src_rate,
|
unsigned src_rate,
|
||||||
ConstBuffer<T> src,
|
std::span<const T> src,
|
||||||
unsigned dest_rate) noexcept
|
unsigned dest_rate) noexcept
|
||||||
{
|
{
|
||||||
unsigned dest_pos = 0;
|
unsigned dest_pos = 0;
|
||||||
unsigned src_frames = src.size / channels;
|
unsigned src_frames = src.size() / channels;
|
||||||
unsigned dest_frames =
|
unsigned dest_frames =
|
||||||
(src_frames * dest_rate + src_rate - 1) / src_rate;
|
(src_frames * dest_rate + src_rate - 1) / src_rate;
|
||||||
unsigned dest_samples = dest_frames * channels;
|
unsigned dest_samples = dest_frames * channels;
|
||||||
size_t dest_size = dest_samples * sizeof(*src.data);
|
size_t dest_size = dest_samples * sizeof(T);
|
||||||
T *dest_buffer = (T *)buffer.Get(dest_size);
|
T *dest_buffer = (T *)buffer.Get(dest_size);
|
||||||
|
|
||||||
assert((src.size % channels) == 0);
|
assert((src.size() % channels) == 0);
|
||||||
|
|
||||||
switch (channels) {
|
switch (channels) {
|
||||||
case 1:
|
case 1:
|
||||||
@ -101,20 +102,20 @@ pcm_resample_fallback(PcmBuffer &buffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static ConstBuffer<void>
|
static std::span<const std::byte>
|
||||||
pcm_resample_fallback_void(PcmBuffer &buffer,
|
pcm_resample_fallback_void(PcmBuffer &buffer,
|
||||||
unsigned channels,
|
unsigned channels,
|
||||||
unsigned src_rate,
|
unsigned src_rate,
|
||||||
ConstBuffer<void> src,
|
std::span<const std::byte> src,
|
||||||
unsigned dest_rate) noexcept
|
unsigned dest_rate) noexcept
|
||||||
{
|
{
|
||||||
const auto typed_src = ConstBuffer<T>::FromVoid(src);
|
const auto typed_src = FromBytesStrict<const T>(src);
|
||||||
return pcm_resample_fallback(buffer, channels, src_rate, typed_src,
|
return std::as_bytes(pcm_resample_fallback(buffer, channels, src_rate, typed_src,
|
||||||
dest_rate).ToVoid();
|
dest_rate));
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
FallbackPcmResampler::Resample(ConstBuffer<void> src)
|
FallbackPcmResampler::Resample(std::span<const std::byte> src)
|
||||||
{
|
{
|
||||||
switch (format.format) {
|
switch (format.format) {
|
||||||
case SampleFormat::UNDEFINED:
|
case SampleFormat::UNDEFINED:
|
||||||
|
@ -24,6 +24,9 @@
|
|||||||
#include "Buffer.hxx"
|
#include "Buffer.hxx"
|
||||||
#include "AudioFormat.hxx"
|
#include "AudioFormat.hxx"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A naive resampler that is used when no external library was found
|
* A naive resampler that is used when no external library was found
|
||||||
* (or when the user explicitly asks for bad quality).
|
* (or when the user explicitly asks for bad quality).
|
||||||
@ -37,7 +40,7 @@ class FallbackPcmResampler final : public PcmResampler {
|
|||||||
public:
|
public:
|
||||||
AudioFormat Open(AudioFormat &af, unsigned new_sample_rate) override;
|
AudioFormat Open(AudioFormat &af, unsigned new_sample_rate) override;
|
||||||
void Close() noexcept override;
|
void Close() noexcept override;
|
||||||
ConstBuffer<void> Resample(ConstBuffer<void> src) override;
|
std::span<const std::byte> Resample(std::span<const std::byte> src) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "FormatConverter.hxx"
|
#include "FormatConverter.hxx"
|
||||||
#include "PcmFormat.hxx"
|
#include "PcmFormat.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -61,8 +60,8 @@ PcmFormatConverter::Close() noexcept
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
PcmFormatConverter::Convert(ConstBuffer<void> src) noexcept
|
PcmFormatConverter::Convert(std::span<const std::byte> src) noexcept
|
||||||
{
|
{
|
||||||
switch (dest_format) {
|
switch (dest_format) {
|
||||||
case SampleFormat::UNDEFINED:
|
case SampleFormat::UNDEFINED:
|
||||||
@ -72,24 +71,24 @@ PcmFormatConverter::Convert(ConstBuffer<void> src) noexcept
|
|||||||
gcc_unreachable();
|
gcc_unreachable();
|
||||||
|
|
||||||
case SampleFormat::S16:
|
case SampleFormat::S16:
|
||||||
return pcm_convert_to_16(buffer, dither,
|
return std::as_bytes(pcm_convert_to_16(buffer, dither,
|
||||||
src_format,
|
src_format,
|
||||||
src).ToVoid();
|
src));
|
||||||
|
|
||||||
case SampleFormat::S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
return pcm_convert_to_24(buffer,
|
return std::as_bytes(pcm_convert_to_24(buffer,
|
||||||
src_format,
|
src_format,
|
||||||
src).ToVoid();
|
src));
|
||||||
|
|
||||||
case SampleFormat::S32:
|
case SampleFormat::S32:
|
||||||
return pcm_convert_to_32(buffer,
|
return std::as_bytes(pcm_convert_to_32(buffer,
|
||||||
src_format,
|
src_format,
|
||||||
src).ToVoid();
|
src));
|
||||||
|
|
||||||
case SampleFormat::FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
return pcm_convert_to_float(buffer,
|
return std::as_bytes(pcm_convert_to_float(buffer,
|
||||||
src_format,
|
src_format,
|
||||||
src).ToVoid();
|
src));
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
|
@ -24,12 +24,12 @@
|
|||||||
#include "Buffer.hxx"
|
#include "Buffer.hxx"
|
||||||
#include "Dither.hxx"
|
#include "Dither.hxx"
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class that converts samples from one format to another.
|
* A class that converts samples from one format to another.
|
||||||
*/
|
*/
|
||||||
@ -73,7 +73,7 @@ public:
|
|||||||
* @return the destination buffer
|
* @return the destination buffer
|
||||||
*/
|
*/
|
||||||
[[gnu::pure]]
|
[[gnu::pure]]
|
||||||
ConstBuffer<void> Convert(ConstBuffer<void> src) noexcept;
|
std::span<const std::byte> Convert(std::span<const std::byte> src) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -71,18 +71,16 @@ GluePcmResampler::Reset() noexcept
|
|||||||
resampler->Reset();
|
resampler->Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
GluePcmResampler::Resample(ConstBuffer<void> src)
|
GluePcmResampler::Resample(std::span<const std::byte> src)
|
||||||
{
|
{
|
||||||
assert(!src.IsNull());
|
|
||||||
|
|
||||||
if (requested_sample_format != src_sample_format)
|
if (requested_sample_format != src_sample_format)
|
||||||
src = format_converter.Convert(src);
|
src = format_converter.Convert(src);
|
||||||
|
|
||||||
return resampler->Resample(src);
|
return resampler->Resample(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
GluePcmResampler::Flush()
|
GluePcmResampler::Flush()
|
||||||
{
|
{
|
||||||
return resampler->Flush();
|
return resampler->Flush();
|
||||||
|
@ -23,9 +23,11 @@
|
|||||||
#include "SampleFormat.hxx"
|
#include "SampleFormat.hxx"
|
||||||
#include "FormatConverter.hxx"
|
#include "FormatConverter.hxx"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
struct AudioFormat;
|
struct AudioFormat;
|
||||||
class PcmResampler;
|
class PcmResampler;
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A glue class that integrates a #PcmResampler and automatically
|
* A glue class that integrates a #PcmResampler and automatically
|
||||||
@ -60,9 +62,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
void Reset() noexcept;
|
void Reset() noexcept;
|
||||||
|
|
||||||
ConstBuffer<void> Resample(ConstBuffer<void> src);
|
std::span<const std::byte> Resample(std::span<const std::byte> src);
|
||||||
|
|
||||||
ConstBuffer<void> Flush();
|
std::span<const std::byte> Flush();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -23,11 +23,11 @@
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
GenericPcmInterleave(uint8_t *gcc_restrict dest,
|
GenericPcmInterleave(uint8_t *gcc_restrict dest,
|
||||||
ConstBuffer<const uint8_t *> src,
|
std::span<const uint8_t *const> src,
|
||||||
size_t n_frames, size_t sample_size) noexcept
|
size_t n_frames, size_t sample_size) noexcept
|
||||||
{
|
{
|
||||||
for (size_t frame = 0; frame < n_frames; ++frame) {
|
for (size_t frame = 0; frame < n_frames; ++frame) {
|
||||||
for (size_t channel = 0; channel < src.size; ++channel) {
|
for (size_t channel = 0; channel < src.size(); ++channel) {
|
||||||
memcpy(dest, src[channel] + frame * sample_size,
|
memcpy(dest, src[channel] + frame * sample_size,
|
||||||
sample_size);
|
sample_size);
|
||||||
dest += sample_size;
|
dest += sample_size;
|
||||||
@ -51,10 +51,10 @@ PcmInterleaveStereo(T *gcc_restrict dest,
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
static void
|
static void
|
||||||
PcmInterleaveT(T *gcc_restrict dest,
|
PcmInterleaveT(T *gcc_restrict dest,
|
||||||
const ConstBuffer<const T *> src,
|
const std::span<const T *const> src,
|
||||||
size_t n_frames) noexcept
|
size_t n_frames) noexcept
|
||||||
{
|
{
|
||||||
switch (src.size) {
|
switch (src.size()) {
|
||||||
case 2:
|
case 2:
|
||||||
PcmInterleaveStereo(dest, src[0], src[1], n_frames);
|
PcmInterleaveStereo(dest, src[0], src[1], n_frames);
|
||||||
return;
|
return;
|
||||||
@ -64,14 +64,14 @@ PcmInterleaveT(T *gcc_restrict dest,
|
|||||||
auto *d = dest++;
|
auto *d = dest++;
|
||||||
|
|
||||||
for (const auto *const s_end = s + n_frames;
|
for (const auto *const s_end = s + n_frames;
|
||||||
s != s_end; ++s, d += src.size)
|
s != s_end; ++s, d += src.size())
|
||||||
*d = *s;
|
*d = *s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
PcmInterleave16(int16_t *gcc_restrict dest,
|
PcmInterleave16(int16_t *gcc_restrict dest,
|
||||||
const ConstBuffer<const int16_t *> src,
|
const std::span<const int16_t *const> src,
|
||||||
size_t n_frames) noexcept
|
size_t n_frames) noexcept
|
||||||
{
|
{
|
||||||
PcmInterleaveT(dest, src, n_frames);
|
PcmInterleaveT(dest, src, n_frames);
|
||||||
@ -79,7 +79,7 @@ PcmInterleave16(int16_t *gcc_restrict dest,
|
|||||||
|
|
||||||
void
|
void
|
||||||
PcmInterleave32(int32_t *gcc_restrict dest,
|
PcmInterleave32(int32_t *gcc_restrict dest,
|
||||||
const ConstBuffer<const int32_t *> src,
|
const std::span<const int32_t *const> src,
|
||||||
size_t n_frames) noexcept
|
size_t n_frames) noexcept
|
||||||
{
|
{
|
||||||
PcmInterleaveT(dest, src, n_frames);
|
PcmInterleaveT(dest, src, n_frames);
|
||||||
@ -87,28 +87,25 @@ PcmInterleave32(int32_t *gcc_restrict dest,
|
|||||||
|
|
||||||
void
|
void
|
||||||
PcmInterleave(void *gcc_restrict dest,
|
PcmInterleave(void *gcc_restrict dest,
|
||||||
ConstBuffer<const void *> src,
|
std::span<const void *const> src,
|
||||||
size_t n_frames, size_t sample_size) noexcept
|
size_t n_frames, size_t sample_size) noexcept
|
||||||
{
|
{
|
||||||
switch (sample_size) {
|
switch (sample_size) {
|
||||||
case 2:
|
case 2:
|
||||||
PcmInterleave16((int16_t *)dest,
|
PcmInterleave16((int16_t *)dest,
|
||||||
ConstBuffer<const int16_t *>((const int16_t *const*)src.data,
|
{(const int16_t *const*)src.data(), src.size()},
|
||||||
src.size),
|
|
||||||
n_frames);
|
n_frames);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
PcmInterleave32((int32_t *)dest,
|
PcmInterleave32((int32_t *)dest,
|
||||||
ConstBuffer<const int32_t *>((const int32_t *const*)src.data,
|
{(const int32_t *const*)src.data(), src.size()},
|
||||||
src.size),
|
|
||||||
n_frames);
|
n_frames);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
GenericPcmInterleave((uint8_t *)dest,
|
GenericPcmInterleave((uint8_t *)dest,
|
||||||
ConstBuffer<const uint8_t *>((const uint8_t *const*)src.data,
|
{(const uint8_t *const*)src.data(), src.size()},
|
||||||
src.size),
|
|
||||||
n_frames, sample_size);
|
n_frames, sample_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,15 +21,16 @@
|
|||||||
#define MPD_PCM_INTERLEAVE_HXX
|
#define MPD_PCM_INTERLEAVE_HXX
|
||||||
|
|
||||||
#include "util/Compiler.h"
|
#include "util/Compiler.h"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interleave planar PCM samples from #src to #dest.
|
* Interleave planar PCM samples from #src to #dest.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
PcmInterleave(void *gcc_restrict dest, ConstBuffer<const void *> src,
|
PcmInterleave(void *gcc_restrict dest, std::span<const void *const> src,
|
||||||
size_t n_frames, size_t sample_size) noexcept;
|
size_t n_frames, size_t sample_size) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,16 +38,18 @@ PcmInterleave(void *gcc_restrict dest, ConstBuffer<const void *> src,
|
|||||||
* per sample).
|
* per sample).
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
PcmInterleave32(int32_t *gcc_restrict dest, ConstBuffer<const int32_t *> src,
|
PcmInterleave32(int32_t *gcc_restrict dest,
|
||||||
|
std::span<const int32_t *const> src,
|
||||||
size_t n_frames) noexcept;
|
size_t n_frames) noexcept;
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
PcmInterleaveFloat(float *gcc_restrict dest, ConstBuffer<const float *> src,
|
PcmInterleaveFloat(float *gcc_restrict dest,
|
||||||
|
std::span<const float *const> src,
|
||||||
size_t n_frames) noexcept
|
size_t n_frames) noexcept
|
||||||
{
|
{
|
||||||
PcmInterleave32((int32_t *)dest,
|
PcmInterleave32((int32_t *)dest,
|
||||||
ConstBuffer<const int32_t *>((const int32_t *const*)src.data,
|
std::span<const int32_t *const>((const int32_t *const*)src.data(),
|
||||||
src.size),
|
src.size()),
|
||||||
n_frames);
|
n_frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "util/ASCII.hxx"
|
#include "util/ASCII.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
|
#include "util/SpanCast.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -120,17 +121,17 @@ LibsampleratePcmResampler::Reset() noexcept
|
|||||||
src_reset(state);
|
src_reset(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ConstBuffer<float>
|
inline std::span<const float>
|
||||||
LibsampleratePcmResampler::Resample2(ConstBuffer<float> src)
|
LibsampleratePcmResampler::Resample2(std::span<const float> src)
|
||||||
{
|
{
|
||||||
assert(src.size % channels == 0);
|
assert(src.size() % channels == 0);
|
||||||
|
|
||||||
const unsigned src_frames = src.size / channels;
|
const unsigned src_frames = src.size() / channels;
|
||||||
const unsigned dest_frames =
|
const unsigned dest_frames =
|
||||||
(src_frames * dest_rate + src_rate - 1) / src_rate;
|
(src_frames * dest_rate + src_rate - 1) / src_rate;
|
||||||
size_t data_out_size = dest_frames * sizeof(float) * channels;
|
size_t data_out_size = dest_frames * sizeof(float) * channels;
|
||||||
|
|
||||||
data.data_in = const_cast<float *>(src.data);
|
data.data_in = const_cast<float *>(src.data());
|
||||||
data.data_out = (float *)buffer.Get(data_out_size);
|
data.data_out = (float *)buffer.Get(data_out_size);
|
||||||
data.input_frames = src_frames;
|
data.input_frames = src_frames;
|
||||||
data.output_frames = dest_frames;
|
data.output_frames = dest_frames;
|
||||||
@ -143,8 +144,8 @@ LibsampleratePcmResampler::Resample2(ConstBuffer<float> src)
|
|||||||
return {data.data_out, size_t(data.output_frames_gen * channels)};
|
return {data.data_out, size_t(data.output_frames_gen * channels)};
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
LibsampleratePcmResampler::Resample(ConstBuffer<void> src)
|
LibsampleratePcmResampler::Resample(std::span<const std::byte> src)
|
||||||
{
|
{
|
||||||
return Resample2(ConstBuffer<float>::FromVoid(src)).ToVoid();
|
return std::as_bytes(Resample2(FromBytesStrict<const float>(src)));
|
||||||
}
|
}
|
||||||
|
@ -44,10 +44,10 @@ public:
|
|||||||
AudioFormat Open(AudioFormat &af, unsigned new_sample_rate) override;
|
AudioFormat Open(AudioFormat &af, unsigned new_sample_rate) override;
|
||||||
void Close() noexcept override;
|
void Close() noexcept override;
|
||||||
void Reset() noexcept override;
|
void Reset() noexcept override;
|
||||||
ConstBuffer<void> Resample(ConstBuffer<void> src) override;
|
std::span<const std::byte> Resample(std::span<const std::byte> src) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConstBuffer<float> Resample2(ConstBuffer<float> src);
|
std::span<const float> Resample2(std::span<const float> src);
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "MixRampAnalyzer.hxx"
|
#include "MixRampAnalyzer.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
MixRampData::Add(MixRampItem item) noexcept
|
MixRampData::Add(MixRampItem item) noexcept
|
||||||
@ -35,20 +36,20 @@ MixRampData::Add(MixRampItem item) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MixRampAnalyzer::Process(ConstBuffer<ReplayGainAnalyzer::Frame> src) noexcept
|
MixRampAnalyzer::Process(std::span<const ReplayGainAnalyzer::Frame> src) noexcept
|
||||||
{
|
{
|
||||||
while (!src.empty()) {
|
while (!src.empty()) {
|
||||||
std::size_t chunk_remaining = chunk_frames - chunk_fill;
|
std::size_t chunk_remaining = chunk_frames - chunk_fill;
|
||||||
assert(chunk_remaining > 0);
|
assert(chunk_remaining > 0);
|
||||||
|
|
||||||
if (chunk_remaining > src.size) {
|
if (chunk_remaining > src.size()) {
|
||||||
gain_analyzer.Process(src);
|
gain_analyzer.Process(src);
|
||||||
chunk_fill += src.size;
|
chunk_fill += src.size();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gain_analyzer.Process({src.data, chunk_remaining});
|
gain_analyzer.Process({src.data(), chunk_remaining});
|
||||||
src.skip_front(chunk_remaining);
|
src = src.subspan(chunk_remaining);
|
||||||
|
|
||||||
gain_analyzer.Flush();
|
gain_analyzer.Flush();
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#include "ReplayGainAnalyzer.hxx"
|
#include "ReplayGainAnalyzer.hxx"
|
||||||
#include "Chrono.hxx"
|
#include "Chrono.hxx"
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
|
||||||
constexpr auto mixramp_volumes = std::array{
|
constexpr auto mixramp_volumes = std::array{
|
||||||
-90., -60., -40., -30., -24., -21., -18.,
|
-90., -60., -40., -30., -24., -21., -18.,
|
||||||
-15., -12., -9., -6., -3., 0., 3., 6.,
|
-15., -12., -9., -6., -3., 0., 3., 6.,
|
||||||
@ -74,7 +76,7 @@ class MixRampAnalyzer {
|
|||||||
std::size_t chunk_fill = 0;
|
std::size_t chunk_fill = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Process(ConstBuffer<ReplayGainAnalyzer::Frame> src) noexcept;
|
void Process(std::span<const ReplayGainAnalyzer::Frame> src) noexcept;
|
||||||
|
|
||||||
FloatDuration GetTime() const noexcept {
|
FloatDuration GetTime() const noexcept {
|
||||||
return chunk_number * chunk_duration;
|
return chunk_number * chunk_duration;
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
#include "MusicPipe.hxx"
|
#include "MusicPipe.hxx"
|
||||||
#include "MusicChunk.hxx"
|
#include "MusicChunk.hxx"
|
||||||
#include "util/Compiler.h"
|
#include "util/Compiler.h"
|
||||||
#include "util/ConstBuffer.hxx"
|
#include "util/SpanCast.hxx"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ AnalyzeMixRamp(const MusicPipe &pipe, const AudioFormat &audio_format,
|
|||||||
|
|
||||||
MixRampAnalyzer a;
|
MixRampAnalyzer a;
|
||||||
do {
|
do {
|
||||||
a.Process(ConstBuffer<ReplayGainAnalyzer::Frame>::FromVoid({chunk->data, chunk->length}));
|
a.Process(FromBytesStrict<const ReplayGainAnalyzer::Frame>({chunk->data, chunk->length}));
|
||||||
} while ((chunk = chunk->next.get()) != nullptr);
|
} while ((chunk = chunk->next.get()) != nullptr);
|
||||||
|
|
||||||
return ToString(a.GetResult(), a.GetTime(), direction);
|
return ToString(a.GetResult(), a.GetTime(), direction);
|
||||||
|
@ -19,8 +19,7 @@
|
|||||||
|
|
||||||
#include "Order.hxx"
|
#include "Order.hxx"
|
||||||
#include "Buffer.hxx"
|
#include "Buffer.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
#include "util/SpanCast.hxx"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* According to:
|
* According to:
|
||||||
@ -109,12 +108,12 @@ ToAlsaChannelOrder50(V *dest, const V *src, size_t n) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
static inline ConstBuffer<V>
|
static inline std::span<const V>
|
||||||
ToAlsaChannelOrder50(PcmBuffer &buffer, ConstBuffer<V> src) noexcept
|
ToAlsaChannelOrder50(PcmBuffer &buffer, std::span<const V> src) noexcept
|
||||||
{
|
{
|
||||||
auto dest = buffer.GetT<V>(src.size);
|
auto dest = buffer.GetT<V>(src.size());
|
||||||
ToAlsaChannelOrder50(dest, src.data, src.size / 5);
|
ToAlsaChannelOrder50(dest, src.data(), src.size() / 5);
|
||||||
return { dest, src.size };
|
return { dest, src.size() };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
@ -127,12 +126,12 @@ ToAlsaChannelOrder51(V *dest, const V *src, size_t n) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
static inline ConstBuffer<V>
|
static inline std::span<const V>
|
||||||
ToAlsaChannelOrder51(PcmBuffer &buffer, ConstBuffer<V> src) noexcept
|
ToAlsaChannelOrder51(PcmBuffer &buffer, std::span<const V> src) noexcept
|
||||||
{
|
{
|
||||||
auto dest = buffer.GetT<V>(src.size);
|
auto dest = buffer.GetT<V>(src.size());
|
||||||
ToAlsaChannelOrder51(dest, src.data, src.size / 6);
|
ToAlsaChannelOrder51(dest, src.data(), src.size() / 6);
|
||||||
return { dest, src.size };
|
return { dest, src.size() };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
@ -145,12 +144,12 @@ ToAlsaChannelOrder70(V *dest, const V *src, size_t n) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
static inline ConstBuffer<V>
|
static inline std::span<const V>
|
||||||
ToAlsaChannelOrder70(PcmBuffer &buffer, ConstBuffer<V> src) noexcept
|
ToAlsaChannelOrder70(PcmBuffer &buffer, std::span<const V> src) noexcept
|
||||||
{
|
{
|
||||||
auto dest = buffer.GetT<V>(src.size);
|
auto dest = buffer.GetT<V>(src.size());
|
||||||
ToAlsaChannelOrder70(dest, src.data, src.size / 7);
|
ToAlsaChannelOrder70(dest, src.data(), src.size() / 7);
|
||||||
return { dest, src.size };
|
return { dest, src.size() };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
@ -163,17 +162,17 @@ ToAlsaChannelOrder71(V *dest, const V *src, size_t n) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
static inline ConstBuffer<V>
|
static inline std::span<const V>
|
||||||
ToAlsaChannelOrder71(PcmBuffer &buffer, ConstBuffer<V> src) noexcept
|
ToAlsaChannelOrder71(PcmBuffer &buffer, std::span<const V> src) noexcept
|
||||||
{
|
{
|
||||||
auto dest = buffer.GetT<V>(src.size);
|
auto dest = buffer.GetT<V>(src.size());
|
||||||
ToAlsaChannelOrder71(dest, src.data, src.size / 8);
|
ToAlsaChannelOrder71(dest, src.data(), src.size() / 8);
|
||||||
return { dest, src.size };
|
return { dest, src.size() };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename V>
|
template<typename V>
|
||||||
static ConstBuffer<V>
|
static std::span<const V>
|
||||||
ToAlsaChannelOrderT(PcmBuffer &buffer, ConstBuffer<V> src,
|
ToAlsaChannelOrderT(PcmBuffer &buffer, std::span<const V> src,
|
||||||
unsigned channels) noexcept
|
unsigned channels) noexcept
|
||||||
{
|
{
|
||||||
switch (channels) {
|
switch (channels) {
|
||||||
@ -194,8 +193,8 @@ ToAlsaChannelOrderT(PcmBuffer &buffer, ConstBuffer<V> src,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
ToAlsaChannelOrder(PcmBuffer &buffer, ConstBuffer<void> src,
|
ToAlsaChannelOrder(PcmBuffer &buffer, std::span<const std::byte> src,
|
||||||
SampleFormat sample_format, unsigned channels) noexcept
|
SampleFormat sample_format, unsigned channels) noexcept
|
||||||
{
|
{
|
||||||
switch (sample_format) {
|
switch (sample_format) {
|
||||||
@ -205,16 +204,16 @@ ToAlsaChannelOrder(PcmBuffer &buffer, ConstBuffer<void> src,
|
|||||||
return src;
|
return src;
|
||||||
|
|
||||||
case SampleFormat::S16:
|
case SampleFormat::S16:
|
||||||
return ToAlsaChannelOrderT(buffer,
|
return std::as_bytes(ToAlsaChannelOrderT(buffer,
|
||||||
ConstBuffer<int16_t>::FromVoid(src),
|
FromBytesStrict<const int16_t>(src),
|
||||||
channels).ToVoid();
|
channels));
|
||||||
|
|
||||||
case SampleFormat::S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
case SampleFormat::S32:
|
case SampleFormat::S32:
|
||||||
case SampleFormat::FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
return ToAlsaChannelOrderT(buffer,
|
return std::as_bytes(ToAlsaChannelOrderT(buffer,
|
||||||
ConstBuffer<int32_t>::FromVoid(src),
|
FromBytesStrict<const int32_t>(src),
|
||||||
channels).ToVoid();
|
channels));
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_unreachable();
|
gcc_unreachable();
|
||||||
|
@ -22,15 +22,16 @@
|
|||||||
|
|
||||||
#include "SampleFormat.hxx"
|
#include "SampleFormat.hxx"
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
|
||||||
class PcmBuffer;
|
class PcmBuffer;
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the given buffer from FLAC channel order
|
* Convert the given buffer from FLAC channel order
|
||||||
* (https://xiph.org/flac/format.html) to ALSA channel order.
|
* (https://xiph.org/flac/format.html) to ALSA channel order.
|
||||||
*/
|
*/
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
ToAlsaChannelOrder(PcmBuffer &buffer, ConstBuffer<void> src,
|
ToAlsaChannelOrder(PcmBuffer &buffer, std::span<const std::byte> src,
|
||||||
SampleFormat sample_format, unsigned channels) noexcept;
|
SampleFormat sample_format, unsigned channels) noexcept;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#include "Buffer.hxx"
|
#include "Buffer.hxx"
|
||||||
#include "Silence.hxx"
|
#include "Silence.hxx"
|
||||||
#include "Traits.hxx"
|
#include "Traits.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -30,11 +29,9 @@
|
|||||||
|
|
||||||
template<typename D, typename S>
|
template<typename D, typename S>
|
||||||
static void
|
static void
|
||||||
MonoToStereo(D dest, S src, S end) noexcept
|
MonoToStereo(D dest, S src) noexcept
|
||||||
{
|
{
|
||||||
while (src != end) {
|
for (const auto value : src) {
|
||||||
const auto value = *src++;
|
|
||||||
|
|
||||||
*dest++ = value;
|
*dest++ = value;
|
||||||
*dest++ = value;
|
*dest++ = value;
|
||||||
}
|
}
|
||||||
@ -55,10 +52,9 @@ StereoToMono(typename Traits::value_type _a,
|
|||||||
template<SampleFormat F, class Traits=SampleTraits<F>>
|
template<SampleFormat F, class Traits=SampleTraits<F>>
|
||||||
static typename Traits::pointer
|
static typename Traits::pointer
|
||||||
StereoToMono(typename Traits::pointer dest,
|
StereoToMono(typename Traits::pointer dest,
|
||||||
typename Traits::const_pointer src,
|
std::span<const typename Traits::value_type> _src) noexcept
|
||||||
typename Traits::const_pointer end) noexcept
|
|
||||||
{
|
{
|
||||||
while (src != end) {
|
for (auto src = _src.begin(), end = _src.end(); src != end;) {
|
||||||
const auto a = *src++;
|
const auto a = *src++;
|
||||||
const auto b = *src++;
|
const auto b = *src++;
|
||||||
|
|
||||||
@ -72,12 +68,11 @@ template<SampleFormat F, class Traits=SampleTraits<F>>
|
|||||||
static typename Traits::pointer
|
static typename Traits::pointer
|
||||||
NToStereo(typename Traits::pointer dest,
|
NToStereo(typename Traits::pointer dest,
|
||||||
unsigned src_channels,
|
unsigned src_channels,
|
||||||
typename Traits::const_pointer src,
|
std::span<const typename Traits::value_type> _src) noexcept
|
||||||
typename Traits::const_pointer end) noexcept
|
|
||||||
{
|
{
|
||||||
assert((end - src) % src_channels == 0);
|
assert(_src.size() % src_channels == 0);
|
||||||
|
|
||||||
while (src != end) {
|
for (auto src = _src.begin(), end = _src.end(); src != end;) {
|
||||||
typename Traits::sum_type sum = *src++;
|
typename Traits::sum_type sum = *src++;
|
||||||
for (unsigned c = 1; c < src_channels; ++c)
|
for (unsigned c = 1; c < src_channels; ++c)
|
||||||
sum += *src++;
|
sum += *src++;
|
||||||
@ -101,16 +96,15 @@ template<SampleFormat F, class Traits=SampleTraits<F>>
|
|||||||
static typename Traits::pointer
|
static typename Traits::pointer
|
||||||
StereoToN(typename Traits::pointer dest,
|
StereoToN(typename Traits::pointer dest,
|
||||||
unsigned dest_channels,
|
unsigned dest_channels,
|
||||||
typename Traits::const_pointer src,
|
std::span<const typename Traits::value_type> _src) noexcept
|
||||||
typename Traits::const_pointer end) noexcept
|
|
||||||
{
|
{
|
||||||
assert(dest_channels > 2);
|
assert(dest_channels > 2);
|
||||||
assert((end - src) % 2 == 0);
|
assert(_src.size() % 2 == 0);
|
||||||
|
|
||||||
std::array<typename Traits::value_type, MAX_CHANNELS - 2> silence;
|
std::array<typename Traits::value_type, MAX_CHANNELS - 2> silence;
|
||||||
PcmSilence(std::as_writable_bytes(std::span{silence}), F);
|
PcmSilence(std::as_writable_bytes(std::span{silence}), F);
|
||||||
|
|
||||||
while (src != end) {
|
for (auto src = _src.begin(), end = _src.end(); src != end;) {
|
||||||
/* copy left/right to front-left/front-right, which is
|
/* copy left/right to front-left/front-right, which is
|
||||||
the first two channels in all multi-channel
|
the first two channels in all multi-channel
|
||||||
configurations **/
|
configurations **/
|
||||||
@ -129,12 +123,11 @@ static typename Traits::pointer
|
|||||||
NToM(typename Traits::pointer dest,
|
NToM(typename Traits::pointer dest,
|
||||||
unsigned dest_channels,
|
unsigned dest_channels,
|
||||||
unsigned src_channels,
|
unsigned src_channels,
|
||||||
typename Traits::const_pointer src,
|
std::span<const typename Traits::value_type> _src) noexcept
|
||||||
typename Traits::const_pointer end) noexcept
|
|
||||||
{
|
{
|
||||||
assert((end - src) % src_channels == 0);
|
assert(_src.size() % src_channels == 0);
|
||||||
|
|
||||||
while (src != end) {
|
for (auto src = _src.begin(), end = _src.end(); src != end;) {
|
||||||
typename Traits::sum_type sum = *src++;
|
typename Traits::sum_type sum = *src++;
|
||||||
for (unsigned c = 1; c < src_channels; ++c)
|
for (unsigned c = 1; c < src_channels; ++c)
|
||||||
sum += *src++;
|
sum += *src++;
|
||||||
@ -150,68 +143,66 @@ NToM(typename Traits::pointer dest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<SampleFormat F, class Traits=SampleTraits<F>>
|
template<SampleFormat F, class Traits=SampleTraits<F>>
|
||||||
static ConstBuffer<typename Traits::value_type>
|
static std::span<const typename Traits::value_type>
|
||||||
ConvertChannels(PcmBuffer &buffer,
|
ConvertChannels(PcmBuffer &buffer,
|
||||||
unsigned dest_channels,
|
unsigned dest_channels,
|
||||||
unsigned src_channels,
|
unsigned src_channels,
|
||||||
ConstBuffer<typename Traits::value_type> src) noexcept
|
std::span<const typename Traits::value_type> src) noexcept
|
||||||
{
|
{
|
||||||
assert(src.size % src_channels == 0);
|
assert(src.size() % src_channels == 0);
|
||||||
|
|
||||||
const size_t dest_size = src.size / src_channels * dest_channels;
|
const size_t dest_size = src.size() / src_channels * dest_channels;
|
||||||
auto dest = buffer.GetT<typename Traits::value_type>(dest_size);
|
auto dest = buffer.GetT<typename Traits::value_type>(dest_size);
|
||||||
|
|
||||||
if (src_channels == 1 && dest_channels == 2)
|
if (src_channels == 1 && dest_channels == 2)
|
||||||
MonoToStereo(dest, src.begin(), src.end());
|
MonoToStereo(dest, src);
|
||||||
else if (src_channels == 2 && dest_channels == 1)
|
else if (src_channels == 2 && dest_channels == 1)
|
||||||
StereoToMono<F>(dest, src.begin(), src.end());
|
StereoToMono<F>(dest, src);
|
||||||
else if (dest_channels == 2)
|
else if (dest_channels == 2)
|
||||||
NToStereo<F>(dest, src_channels, src.begin(), src.end());
|
NToStereo<F>(dest, src_channels, src);
|
||||||
else if (src_channels == 2 && dest_channels > 2)
|
else if (src_channels == 2 && dest_channels > 2)
|
||||||
StereoToN<F, Traits>(dest, dest_channels,
|
StereoToN<F, Traits>(dest, dest_channels, src);
|
||||||
src.begin(), src.end());
|
|
||||||
else
|
else
|
||||||
NToM<F>(dest, dest_channels,
|
NToM<F>(dest, dest_channels, src_channels, src);
|
||||||
src_channels, src.begin(), src.end());
|
|
||||||
|
|
||||||
return { dest, dest_size };
|
return { dest, dest_size };
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<int16_t>
|
std::span<const int16_t>
|
||||||
pcm_convert_channels_16(PcmBuffer &buffer,
|
pcm_convert_channels_16(PcmBuffer &buffer,
|
||||||
unsigned dest_channels,
|
unsigned dest_channels,
|
||||||
unsigned src_channels,
|
unsigned src_channels,
|
||||||
ConstBuffer<int16_t> src) noexcept
|
std::span<const int16_t> src) noexcept
|
||||||
{
|
{
|
||||||
return ConvertChannels<SampleFormat::S16>(buffer, dest_channels,
|
return ConvertChannels<SampleFormat::S16>(buffer, dest_channels,
|
||||||
src_channels, src);
|
src_channels, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<int32_t>
|
std::span<const int32_t>
|
||||||
pcm_convert_channels_24(PcmBuffer &buffer,
|
pcm_convert_channels_24(PcmBuffer &buffer,
|
||||||
unsigned dest_channels,
|
unsigned dest_channels,
|
||||||
unsigned src_channels,
|
unsigned src_channels,
|
||||||
ConstBuffer<int32_t> src) noexcept
|
std::span<const int32_t> src) noexcept
|
||||||
{
|
{
|
||||||
return ConvertChannels<SampleFormat::S24_P32>(buffer, dest_channels,
|
return ConvertChannels<SampleFormat::S24_P32>(buffer, dest_channels,
|
||||||
src_channels, src);
|
src_channels, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<int32_t>
|
std::span<const int32_t>
|
||||||
pcm_convert_channels_32(PcmBuffer &buffer,
|
pcm_convert_channels_32(PcmBuffer &buffer,
|
||||||
unsigned dest_channels,
|
unsigned dest_channels,
|
||||||
unsigned src_channels,
|
unsigned src_channels,
|
||||||
ConstBuffer<int32_t> src) noexcept
|
std::span<const int32_t> src) noexcept
|
||||||
{
|
{
|
||||||
return ConvertChannels<SampleFormat::S32>(buffer, dest_channels,
|
return ConvertChannels<SampleFormat::S32>(buffer, dest_channels,
|
||||||
src_channels, src);
|
src_channels, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<float>
|
std::span<const float>
|
||||||
pcm_convert_channels_float(PcmBuffer &buffer,
|
pcm_convert_channels_float(PcmBuffer &buffer,
|
||||||
unsigned dest_channels,
|
unsigned dest_channels,
|
||||||
unsigned src_channels,
|
unsigned src_channels,
|
||||||
ConstBuffer<float> src) noexcept
|
std::span<const float> src) noexcept
|
||||||
{
|
{
|
||||||
return ConvertChannels<SampleFormat::FLOAT>(buffer, dest_channels,
|
return ConvertChannels<SampleFormat::FLOAT>(buffer, dest_channels,
|
||||||
src_channels, src);
|
src_channels, src);
|
||||||
|
@ -21,9 +21,9 @@
|
|||||||
#define MPD_PCM_CHANNELS_HXX
|
#define MPD_PCM_CHANNELS_HXX
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
class PcmBuffer;
|
class PcmBuffer;
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the number of channels in 16 bit PCM data.
|
* Changes the number of channels in 16 bit PCM data.
|
||||||
@ -34,11 +34,11 @@ template<typename T> struct ConstBuffer;
|
|||||||
* @param src the source PCM buffer
|
* @param src the source PCM buffer
|
||||||
* @return the destination buffer
|
* @return the destination buffer
|
||||||
*/
|
*/
|
||||||
ConstBuffer<int16_t>
|
std::span<const int16_t>
|
||||||
pcm_convert_channels_16(PcmBuffer &buffer,
|
pcm_convert_channels_16(PcmBuffer &buffer,
|
||||||
unsigned dest_channels,
|
unsigned dest_channels,
|
||||||
unsigned src_channels,
|
unsigned src_channels,
|
||||||
ConstBuffer<int16_t> src) noexcept;
|
std::span<const int16_t> src) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the number of channels in 24 bit PCM data (aligned at 32
|
* Changes the number of channels in 24 bit PCM data (aligned at 32
|
||||||
@ -50,11 +50,11 @@ pcm_convert_channels_16(PcmBuffer &buffer,
|
|||||||
* @param src the source PCM buffer
|
* @param src the source PCM buffer
|
||||||
* @return the destination buffer
|
* @return the destination buffer
|
||||||
*/
|
*/
|
||||||
ConstBuffer<int32_t>
|
std::span<const int32_t>
|
||||||
pcm_convert_channels_24(PcmBuffer &buffer,
|
pcm_convert_channels_24(PcmBuffer &buffer,
|
||||||
unsigned dest_channels,
|
unsigned dest_channels,
|
||||||
unsigned src_channels,
|
unsigned src_channels,
|
||||||
ConstBuffer<int32_t> src) noexcept;
|
std::span<const int32_t> src) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the number of channels in 32 bit PCM data.
|
* Changes the number of channels in 32 bit PCM data.
|
||||||
@ -65,11 +65,11 @@ pcm_convert_channels_24(PcmBuffer &buffer,
|
|||||||
* @param src the source PCM buffer
|
* @param src the source PCM buffer
|
||||||
* @return the destination buffer
|
* @return the destination buffer
|
||||||
*/
|
*/
|
||||||
ConstBuffer<int32_t>
|
std::span<const int32_t>
|
||||||
pcm_convert_channels_32(PcmBuffer &buffer,
|
pcm_convert_channels_32(PcmBuffer &buffer,
|
||||||
unsigned dest_channels,
|
unsigned dest_channels,
|
||||||
unsigned src_channels,
|
unsigned src_channels,
|
||||||
ConstBuffer<int32_t> src) noexcept;
|
std::span<const int32_t> src) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the number of channels in 32 bit float PCM data.
|
* Changes the number of channels in 32 bit float PCM data.
|
||||||
@ -80,10 +80,10 @@ pcm_convert_channels_32(PcmBuffer &buffer,
|
|||||||
* @param src the source PCM buffer
|
* @param src the source PCM buffer
|
||||||
* @return the destination buffer
|
* @return the destination buffer
|
||||||
*/
|
*/
|
||||||
ConstBuffer<float>
|
std::span<const float>
|
||||||
pcm_convert_channels_float(PcmBuffer &buffer,
|
pcm_convert_channels_float(PcmBuffer &buffer,
|
||||||
unsigned dest_channels,
|
unsigned dest_channels,
|
||||||
unsigned src_channels,
|
unsigned src_channels,
|
||||||
ConstBuffer<float> src) noexcept;
|
std::span<const float> src) noexcept;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -19,38 +19,35 @@
|
|||||||
|
|
||||||
#include "PcmDsd.hxx"
|
#include "PcmDsd.hxx"
|
||||||
#include "Dsd2Pcm.hxx"
|
#include "Dsd2Pcm.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
ConstBuffer<float>
|
std::span<const float>
|
||||||
PcmDsd::ToFloat(unsigned channels, ConstBuffer<uint8_t> src) noexcept
|
PcmDsd::ToFloat(unsigned channels, std::span<const uint8_t> src) noexcept
|
||||||
{
|
{
|
||||||
assert(!src.IsNull());
|
|
||||||
assert(!src.empty());
|
assert(!src.empty());
|
||||||
assert(src.size % channels == 0);
|
assert(src.size() % channels == 0);
|
||||||
|
|
||||||
const size_t num_samples = src.size;
|
const size_t num_samples = src.size();
|
||||||
const size_t num_frames = src.size / channels;
|
const size_t num_frames = src.size() / channels;
|
||||||
|
|
||||||
auto *dest = buffer.GetT<float>(num_samples);
|
auto *dest = buffer.GetT<float>(num_samples);
|
||||||
|
|
||||||
dsd2pcm.Translate(channels, num_frames, src.data, dest);
|
dsd2pcm.Translate(channels, num_frames, src.data(), dest);
|
||||||
return { dest, num_samples };
|
return { dest, num_samples };
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<int32_t>
|
std::span<const int32_t>
|
||||||
PcmDsd::ToS24(unsigned channels, ConstBuffer<uint8_t> src) noexcept
|
PcmDsd::ToS24(unsigned channels, std::span<const uint8_t> src) noexcept
|
||||||
{
|
{
|
||||||
assert(!src.IsNull());
|
|
||||||
assert(!src.empty());
|
assert(!src.empty());
|
||||||
assert(src.size % channels == 0);
|
assert(src.size() % channels == 0);
|
||||||
|
|
||||||
const size_t num_samples = src.size;
|
const size_t num_samples = src.size();
|
||||||
const size_t num_frames = src.size / channels;
|
const size_t num_frames = src.size() / channels;
|
||||||
|
|
||||||
auto *dest = buffer.GetT<int32_t>(num_samples);
|
auto *dest = buffer.GetT<int32_t>(num_samples);
|
||||||
|
|
||||||
dsd2pcm.TranslateS24(channels, num_frames, src.data, dest);
|
dsd2pcm.TranslateS24(channels, num_frames, src.data(), dest);
|
||||||
return { dest, num_samples };
|
return { dest, num_samples };
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,7 @@
|
|||||||
#include "Dsd2Pcm.hxx"
|
#include "Dsd2Pcm.hxx"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for the dsd2pcm library.
|
* Wrapper for the dsd2pcm library.
|
||||||
@ -40,11 +39,11 @@ public:
|
|||||||
dsd2pcm.Reset();
|
dsd2pcm.Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<float> ToFloat(unsigned channels,
|
std::span<const float> ToFloat(unsigned channels,
|
||||||
ConstBuffer<uint8_t> src) noexcept;
|
std::span<const uint8_t> src) noexcept;
|
||||||
|
|
||||||
ConstBuffer<int32_t> ToS24(unsigned channels,
|
std::span<const int32_t> ToS24(unsigned channels,
|
||||||
ConstBuffer<uint8_t> src) noexcept;
|
std::span<const uint8_t> src) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
#include "Traits.hxx"
|
#include "Traits.hxx"
|
||||||
#include "FloatConvert.hxx"
|
#include "FloatConvert.hxx"
|
||||||
#include "ShiftConvert.hxx"
|
#include "ShiftConvert.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
#include "util/SpanCast.hxx"
|
||||||
#include "util/TransformN.hxx"
|
#include "util/TransformN.hxx"
|
||||||
|
|
||||||
#include "Dither.cxx" // including the .cxx file to get inlined templates
|
#include "Dither.cxx" // including the .cxx file to get inlined templates
|
||||||
@ -115,51 +115,51 @@ struct FloatToInteger<SampleFormat::S16, SampleTraits<SampleFormat::S16>>
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<class C>
|
template<class C>
|
||||||
static ConstBuffer<typename C::DstTraits::value_type>
|
static std::span<const typename C::DstTraits::value_type>
|
||||||
AllocateConvert(PcmBuffer &buffer, C convert,
|
AllocateConvert(PcmBuffer &buffer, C convert,
|
||||||
ConstBuffer<typename C::SrcTraits::value_type> src)
|
std::span<const typename C::SrcTraits::value_type> src)
|
||||||
{
|
{
|
||||||
auto dest = buffer.GetT<typename C::DstTraits::value_type>(src.size);
|
auto dest = buffer.GetT<typename C::DstTraits::value_type>(src.size());
|
||||||
convert.Convert(dest, src.data, src.size);
|
convert.Convert(dest, src.data(), src.size());
|
||||||
return { dest, src.size };
|
return { dest, src.size() };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<SampleFormat F, class Traits=SampleTraits<F>>
|
template<SampleFormat F, class Traits=SampleTraits<F>>
|
||||||
static ConstBuffer<typename Traits::value_type>
|
static std::span<const typename Traits::value_type>
|
||||||
AllocateFromFloat(PcmBuffer &buffer, ConstBuffer<float> src)
|
AllocateFromFloat(PcmBuffer &buffer, std::span<const float> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, FloatToInteger<F, Traits>(), src);
|
return AllocateConvert(buffer, FloatToInteger<F, Traits>(), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstBuffer<int16_t>
|
static std::span<const int16_t>
|
||||||
pcm_allocate_8_to_16(PcmBuffer &buffer, ConstBuffer<int8_t> src)
|
pcm_allocate_8_to_16(PcmBuffer &buffer, std::span<const int8_t> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, Convert8To16(), src);
|
return AllocateConvert(buffer, Convert8To16(), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstBuffer<int16_t>
|
static std::span<const int16_t>
|
||||||
pcm_allocate_24p32_to_16(PcmBuffer &buffer, PcmDither &dither,
|
pcm_allocate_24p32_to_16(PcmBuffer &buffer, PcmDither &dither,
|
||||||
ConstBuffer<int32_t> src)
|
std::span<const int32_t> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, Convert24To16(dither), src);
|
return AllocateConvert(buffer, Convert24To16(dither), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstBuffer<int16_t>
|
static std::span<const int16_t>
|
||||||
pcm_allocate_32_to_16(PcmBuffer &buffer, PcmDither &dither,
|
pcm_allocate_32_to_16(PcmBuffer &buffer, PcmDither &dither,
|
||||||
ConstBuffer<int32_t> src)
|
std::span<const int32_t> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, Convert32To16(dither), src);
|
return AllocateConvert(buffer, Convert32To16(dither), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstBuffer<int16_t>
|
static std::span<const int16_t>
|
||||||
pcm_allocate_float_to_16(PcmBuffer &buffer, ConstBuffer<float> src)
|
pcm_allocate_float_to_16(PcmBuffer &buffer, std::span<const float> src)
|
||||||
{
|
{
|
||||||
return AllocateFromFloat<SampleFormat::S16>(buffer, src);
|
return AllocateFromFloat<SampleFormat::S16>(buffer, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<int16_t>
|
std::span<const int16_t>
|
||||||
pcm_convert_to_16(PcmBuffer &buffer, PcmDither &dither,
|
pcm_convert_to_16(PcmBuffer &buffer, PcmDither &dither,
|
||||||
SampleFormat src_format, ConstBuffer<void> src) noexcept
|
SampleFormat src_format, std::span<const std::byte> src) noexcept
|
||||||
{
|
{
|
||||||
switch (src_format) {
|
switch (src_format) {
|
||||||
case SampleFormat::UNDEFINED:
|
case SampleFormat::UNDEFINED:
|
||||||
@ -168,25 +168,25 @@ pcm_convert_to_16(PcmBuffer &buffer, PcmDither &dither,
|
|||||||
|
|
||||||
case SampleFormat::S8:
|
case SampleFormat::S8:
|
||||||
return pcm_allocate_8_to_16(buffer,
|
return pcm_allocate_8_to_16(buffer,
|
||||||
ConstBuffer<int8_t>::FromVoid(src));
|
FromBytesStrict<const int8_t>(src));
|
||||||
|
|
||||||
case SampleFormat::S16:
|
case SampleFormat::S16:
|
||||||
return ConstBuffer<int16_t>::FromVoid(src);
|
return FromBytesStrict<const int16_t>(src);
|
||||||
|
|
||||||
case SampleFormat::S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
return pcm_allocate_24p32_to_16(buffer, dither,
|
return pcm_allocate_24p32_to_16(buffer, dither,
|
||||||
ConstBuffer<int32_t>::FromVoid(src));
|
FromBytesStrict<const int32_t>(src));
|
||||||
|
|
||||||
case SampleFormat::S32:
|
case SampleFormat::S32:
|
||||||
return pcm_allocate_32_to_16(buffer, dither,
|
return pcm_allocate_32_to_16(buffer, dither,
|
||||||
ConstBuffer<int32_t>::FromVoid(src));
|
FromBytesStrict<const int32_t>(src));
|
||||||
|
|
||||||
case SampleFormat::FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
return pcm_allocate_float_to_16(buffer,
|
return pcm_allocate_float_to_16(buffer,
|
||||||
ConstBuffer<float>::FromVoid(src));
|
FromBytesStrict<const float>(src));
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Convert8To24
|
struct Convert8To24
|
||||||
@ -197,14 +197,14 @@ struct Convert16To24
|
|||||||
: PerSampleConvert<LeftShiftSampleConvert<SampleFormat::S16,
|
: PerSampleConvert<LeftShiftSampleConvert<SampleFormat::S16,
|
||||||
SampleFormat::S24_P32>> {};
|
SampleFormat::S24_P32>> {};
|
||||||
|
|
||||||
static ConstBuffer<int32_t>
|
static std::span<const int32_t>
|
||||||
pcm_allocate_8_to_24(PcmBuffer &buffer, ConstBuffer<int8_t> src)
|
pcm_allocate_8_to_24(PcmBuffer &buffer, std::span<const int8_t> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, Convert8To24(), src);
|
return AllocateConvert(buffer, Convert8To24(), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstBuffer<int32_t>
|
static std::span<const int32_t>
|
||||||
pcm_allocate_16_to_24(PcmBuffer &buffer, ConstBuffer<int16_t> src)
|
pcm_allocate_16_to_24(PcmBuffer &buffer, std::span<const int16_t> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, Convert16To24(), src);
|
return AllocateConvert(buffer, Convert16To24(), src);
|
||||||
}
|
}
|
||||||
@ -213,21 +213,21 @@ struct Convert32To24
|
|||||||
: PerSampleConvert<RightShiftSampleConvert<SampleFormat::S32,
|
: PerSampleConvert<RightShiftSampleConvert<SampleFormat::S32,
|
||||||
SampleFormat::S24_P32>> {};
|
SampleFormat::S24_P32>> {};
|
||||||
|
|
||||||
static ConstBuffer<int32_t>
|
static std::span<const int32_t>
|
||||||
pcm_allocate_32_to_24(PcmBuffer &buffer, ConstBuffer<int32_t> src)
|
pcm_allocate_32_to_24(PcmBuffer &buffer, std::span<const int32_t> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, Convert32To24(), src);
|
return AllocateConvert(buffer, Convert32To24(), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstBuffer<int32_t>
|
static std::span<const int32_t>
|
||||||
pcm_allocate_float_to_24(PcmBuffer &buffer, ConstBuffer<float> src)
|
pcm_allocate_float_to_24(PcmBuffer &buffer, std::span<const float> src)
|
||||||
{
|
{
|
||||||
return AllocateFromFloat<SampleFormat::S24_P32>(buffer, src);
|
return AllocateFromFloat<SampleFormat::S24_P32>(buffer, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<int32_t>
|
std::span<const int32_t>
|
||||||
pcm_convert_to_24(PcmBuffer &buffer,
|
pcm_convert_to_24(PcmBuffer &buffer,
|
||||||
SampleFormat src_format, ConstBuffer<void> src) noexcept
|
SampleFormat src_format, std::span<const std::byte> src) noexcept
|
||||||
{
|
{
|
||||||
switch (src_format) {
|
switch (src_format) {
|
||||||
case SampleFormat::UNDEFINED:
|
case SampleFormat::UNDEFINED:
|
||||||
@ -236,25 +236,25 @@ pcm_convert_to_24(PcmBuffer &buffer,
|
|||||||
|
|
||||||
case SampleFormat::S8:
|
case SampleFormat::S8:
|
||||||
return pcm_allocate_8_to_24(buffer,
|
return pcm_allocate_8_to_24(buffer,
|
||||||
ConstBuffer<int8_t>::FromVoid(src));
|
FromBytesStrict<const int8_t>(src));
|
||||||
|
|
||||||
case SampleFormat::S16:
|
case SampleFormat::S16:
|
||||||
return pcm_allocate_16_to_24(buffer,
|
return pcm_allocate_16_to_24(buffer,
|
||||||
ConstBuffer<int16_t>::FromVoid(src));
|
FromBytesStrict<const int16_t>(src));
|
||||||
|
|
||||||
case SampleFormat::S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
return ConstBuffer<int32_t>::FromVoid(src);
|
return FromBytesStrict<const int32_t>(src);
|
||||||
|
|
||||||
case SampleFormat::S32:
|
case SampleFormat::S32:
|
||||||
return pcm_allocate_32_to_24(buffer,
|
return pcm_allocate_32_to_24(buffer,
|
||||||
ConstBuffer<int32_t>::FromVoid(src));
|
FromBytesStrict<const int32_t>(src));
|
||||||
|
|
||||||
case SampleFormat::FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
return pcm_allocate_float_to_24(buffer,
|
return pcm_allocate_float_to_24(buffer,
|
||||||
ConstBuffer<float>::FromVoid(src));
|
FromBytesStrict<const float>(src));
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Convert8To32
|
struct Convert8To32
|
||||||
@ -269,33 +269,33 @@ struct Convert24To32
|
|||||||
: PerSampleConvert<LeftShiftSampleConvert<SampleFormat::S24_P32,
|
: PerSampleConvert<LeftShiftSampleConvert<SampleFormat::S24_P32,
|
||||||
SampleFormat::S32>> {};
|
SampleFormat::S32>> {};
|
||||||
|
|
||||||
static ConstBuffer<int32_t>
|
static std::span<const int32_t>
|
||||||
pcm_allocate_8_to_32(PcmBuffer &buffer, ConstBuffer<int8_t> src)
|
pcm_allocate_8_to_32(PcmBuffer &buffer, std::span<const int8_t> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, Convert8To32(), src);
|
return AllocateConvert(buffer, Convert8To32(), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstBuffer<int32_t>
|
static std::span<const int32_t>
|
||||||
pcm_allocate_16_to_32(PcmBuffer &buffer, ConstBuffer<int16_t> src)
|
pcm_allocate_16_to_32(PcmBuffer &buffer, std::span<const int16_t> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, Convert16To32(), src);
|
return AllocateConvert(buffer, Convert16To32(), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstBuffer<int32_t>
|
static std::span<const int32_t>
|
||||||
pcm_allocate_24p32_to_32(PcmBuffer &buffer, ConstBuffer<int32_t> src)
|
pcm_allocate_24p32_to_32(PcmBuffer &buffer, std::span<const int32_t> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, Convert24To32(), src);
|
return AllocateConvert(buffer, Convert24To32(), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstBuffer<int32_t>
|
static std::span<const int32_t>
|
||||||
pcm_allocate_float_to_32(PcmBuffer &buffer, ConstBuffer<float> src)
|
pcm_allocate_float_to_32(PcmBuffer &buffer, std::span<const float> src)
|
||||||
{
|
{
|
||||||
return AllocateFromFloat<SampleFormat::S32>(buffer, src);
|
return AllocateFromFloat<SampleFormat::S32>(buffer, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<int32_t>
|
std::span<const int32_t>
|
||||||
pcm_convert_to_32(PcmBuffer &buffer,
|
pcm_convert_to_32(PcmBuffer &buffer,
|
||||||
SampleFormat src_format, ConstBuffer<void> src) noexcept
|
SampleFormat src_format, std::span<const std::byte> src) noexcept
|
||||||
{
|
{
|
||||||
switch (src_format) {
|
switch (src_format) {
|
||||||
case SampleFormat::UNDEFINED:
|
case SampleFormat::UNDEFINED:
|
||||||
@ -304,25 +304,25 @@ pcm_convert_to_32(PcmBuffer &buffer,
|
|||||||
|
|
||||||
case SampleFormat::S8:
|
case SampleFormat::S8:
|
||||||
return pcm_allocate_8_to_32(buffer,
|
return pcm_allocate_8_to_32(buffer,
|
||||||
ConstBuffer<int8_t>::FromVoid(src));
|
FromBytesStrict<const int8_t>(src));
|
||||||
|
|
||||||
case SampleFormat::S16:
|
case SampleFormat::S16:
|
||||||
return pcm_allocate_16_to_32(buffer,
|
return pcm_allocate_16_to_32(buffer,
|
||||||
ConstBuffer<int16_t>::FromVoid(src));
|
FromBytesStrict<const int16_t>(src));
|
||||||
|
|
||||||
case SampleFormat::S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
return pcm_allocate_24p32_to_32(buffer,
|
return pcm_allocate_24p32_to_32(buffer,
|
||||||
ConstBuffer<int32_t>::FromVoid(src));
|
FromBytesStrict<const int32_t>(src));
|
||||||
|
|
||||||
case SampleFormat::S32:
|
case SampleFormat::S32:
|
||||||
return ConstBuffer<int32_t>::FromVoid(src);
|
return FromBytesStrict<const int32_t>(src);
|
||||||
|
|
||||||
case SampleFormat::FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
return pcm_allocate_float_to_32(buffer,
|
return pcm_allocate_float_to_32(buffer,
|
||||||
ConstBuffer<float>::FromVoid(src));
|
FromBytesStrict<const float>(src));
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Convert8ToFloat
|
struct Convert8ToFloat
|
||||||
@ -337,33 +337,33 @@ struct Convert24ToFloat
|
|||||||
struct Convert32ToFloat
|
struct Convert32ToFloat
|
||||||
: PerSampleConvert<IntegerToFloatSampleConvert<SampleFormat::S32>> {};
|
: PerSampleConvert<IntegerToFloatSampleConvert<SampleFormat::S32>> {};
|
||||||
|
|
||||||
static ConstBuffer<float>
|
static std::span<const float>
|
||||||
pcm_allocate_8_to_float(PcmBuffer &buffer, ConstBuffer<int8_t> src)
|
pcm_allocate_8_to_float(PcmBuffer &buffer, std::span<const int8_t> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, Convert8ToFloat(), src);
|
return AllocateConvert(buffer, Convert8ToFloat(), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstBuffer<float>
|
static std::span<const float>
|
||||||
pcm_allocate_16_to_float(PcmBuffer &buffer, ConstBuffer<int16_t> src)
|
pcm_allocate_16_to_float(PcmBuffer &buffer, std::span<const int16_t> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, Convert16ToFloat(), src);
|
return AllocateConvert(buffer, Convert16ToFloat(), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstBuffer<float>
|
static std::span<const float>
|
||||||
pcm_allocate_24p32_to_float(PcmBuffer &buffer, ConstBuffer<int32_t> src)
|
pcm_allocate_24p32_to_float(PcmBuffer &buffer, std::span<const int32_t> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, Convert24ToFloat(), src);
|
return AllocateConvert(buffer, Convert24ToFloat(), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConstBuffer<float>
|
static std::span<const float>
|
||||||
pcm_allocate_32_to_float(PcmBuffer &buffer, ConstBuffer<int32_t> src)
|
pcm_allocate_32_to_float(PcmBuffer &buffer, std::span<const int32_t> src)
|
||||||
{
|
{
|
||||||
return AllocateConvert(buffer, Convert32ToFloat(), src);
|
return AllocateConvert(buffer, Convert32ToFloat(), src);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<float>
|
std::span<const float>
|
||||||
pcm_convert_to_float(PcmBuffer &buffer,
|
pcm_convert_to_float(PcmBuffer &buffer,
|
||||||
SampleFormat src_format, ConstBuffer<void> src) noexcept
|
SampleFormat src_format, std::span<const std::byte> src) noexcept
|
||||||
{
|
{
|
||||||
switch (src_format) {
|
switch (src_format) {
|
||||||
case SampleFormat::UNDEFINED:
|
case SampleFormat::UNDEFINED:
|
||||||
@ -372,23 +372,23 @@ pcm_convert_to_float(PcmBuffer &buffer,
|
|||||||
|
|
||||||
case SampleFormat::S8:
|
case SampleFormat::S8:
|
||||||
return pcm_allocate_8_to_float(buffer,
|
return pcm_allocate_8_to_float(buffer,
|
||||||
ConstBuffer<int8_t>::FromVoid(src));
|
FromBytesStrict<const int8_t>(src));
|
||||||
|
|
||||||
case SampleFormat::S16:
|
case SampleFormat::S16:
|
||||||
return pcm_allocate_16_to_float(buffer,
|
return pcm_allocate_16_to_float(buffer,
|
||||||
ConstBuffer<int16_t>::FromVoid(src));
|
FromBytesStrict<const int16_t>(src));
|
||||||
|
|
||||||
case SampleFormat::S32:
|
case SampleFormat::S32:
|
||||||
return pcm_allocate_32_to_float(buffer,
|
return pcm_allocate_32_to_float(buffer,
|
||||||
ConstBuffer<int32_t>::FromVoid(src));
|
FromBytesStrict<const int32_t>(src));
|
||||||
|
|
||||||
case SampleFormat::S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
return pcm_allocate_24p32_to_float(buffer,
|
return pcm_allocate_24p32_to_float(buffer,
|
||||||
ConstBuffer<int32_t>::FromVoid(src));
|
FromBytesStrict<const int32_t>(src));
|
||||||
|
|
||||||
case SampleFormat::FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
return ConstBuffer<float>::FromVoid(src);
|
return FromBytesStrict<const float>(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@
|
|||||||
#include "SampleFormat.hxx"
|
#include "SampleFormat.hxx"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
class PcmBuffer;
|
class PcmBuffer;
|
||||||
class PcmDither;
|
class PcmDither;
|
||||||
|
|
||||||
@ -38,9 +38,9 @@ class PcmDither;
|
|||||||
* @return the destination buffer
|
* @return the destination buffer
|
||||||
*/
|
*/
|
||||||
[[gnu::pure]]
|
[[gnu::pure]]
|
||||||
ConstBuffer<int16_t>
|
std::span<const int16_t>
|
||||||
pcm_convert_to_16(PcmBuffer &buffer, PcmDither &dither,
|
pcm_convert_to_16(PcmBuffer &buffer, PcmDither &dither,
|
||||||
SampleFormat src_format, ConstBuffer<void> src) noexcept;
|
SampleFormat src_format, std::span<const std::byte> src) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts PCM samples to 24 bit (32 bit alignment).
|
* Converts PCM samples to 24 bit (32 bit alignment).
|
||||||
@ -50,9 +50,9 @@ pcm_convert_to_16(PcmBuffer &buffer, PcmDither &dither,
|
|||||||
* @return the destination buffer
|
* @return the destination buffer
|
||||||
*/
|
*/
|
||||||
[[gnu::pure]]
|
[[gnu::pure]]
|
||||||
ConstBuffer<int32_t>
|
std::span<const int32_t>
|
||||||
pcm_convert_to_24(PcmBuffer &buffer,
|
pcm_convert_to_24(PcmBuffer &buffer,
|
||||||
SampleFormat src_format, ConstBuffer<void> src) noexcept;
|
SampleFormat src_format, std::span<const std::byte> src) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts PCM samples to 32 bit.
|
* Converts PCM samples to 32 bit.
|
||||||
@ -62,9 +62,9 @@ pcm_convert_to_24(PcmBuffer &buffer,
|
|||||||
* @return the destination buffer
|
* @return the destination buffer
|
||||||
*/
|
*/
|
||||||
[[gnu::pure]]
|
[[gnu::pure]]
|
||||||
ConstBuffer<int32_t>
|
std::span<const int32_t>
|
||||||
pcm_convert_to_32(PcmBuffer &buffer,
|
pcm_convert_to_32(PcmBuffer &buffer,
|
||||||
SampleFormat src_format, ConstBuffer<void> src) noexcept;
|
SampleFormat src_format, std::span<const std::byte> src) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts PCM samples to 32 bit floating point.
|
* Converts PCM samples to 32 bit floating point.
|
||||||
@ -74,8 +74,8 @@ pcm_convert_to_32(PcmBuffer &buffer,
|
|||||||
* @return the destination buffer
|
* @return the destination buffer
|
||||||
*/
|
*/
|
||||||
[[gnu::pure]]
|
[[gnu::pure]]
|
||||||
ConstBuffer<float>
|
std::span<const float>
|
||||||
pcm_convert_to_float(PcmBuffer &buffer,
|
pcm_convert_to_float(PcmBuffer &buffer,
|
||||||
SampleFormat src_format, ConstBuffer<void> src) noexcept;
|
SampleFormat src_format, std::span<const std::byte> src) noexcept;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
#include "ReplayGainAnalyzer.hxx"
|
#include "ReplayGainAnalyzer.hxx"
|
||||||
#include "util/Compiler.h"
|
#include "util/Compiler.h"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -85,7 +84,7 @@ SquareHypot(ReplayGainAnalyzer::Frame f) noexcept
|
|||||||
*/
|
*/
|
||||||
[[gnu::hot]]
|
[[gnu::hot]]
|
||||||
static double
|
static double
|
||||||
CalcStereoRMS(ConstBuffer<ReplayGainAnalyzer::Frame> src) noexcept
|
CalcStereoRMS(std::span<const ReplayGainAnalyzer::Frame> src) noexcept
|
||||||
{
|
{
|
||||||
#if GCC_OLDER_THAN(10,0)
|
#if GCC_OLDER_THAN(10,0)
|
||||||
/* GCC 8 doesn't have std::transform_reduce() */
|
/* GCC 8 doesn't have std::transform_reduce() */
|
||||||
@ -100,7 +99,7 @@ CalcStereoRMS(ConstBuffer<ReplayGainAnalyzer::Frame> src) noexcept
|
|||||||
SquareHypot);
|
SquareHypot);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 10 * std::log10(sum / src.size) + 90.0 - 3.0;
|
return 10 * std::log10(sum / src.size()) + 90.0 - 3.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr bool
|
static constexpr bool
|
||||||
@ -118,7 +117,7 @@ IsSilentFrame(ReplayGainAnalyzer::Frame frame) noexcept
|
|||||||
|
|
||||||
[[gnu::pure]]
|
[[gnu::pure]]
|
||||||
static bool
|
static bool
|
||||||
IsSilentBuffer(ConstBuffer<ReplayGainAnalyzer::Frame> buffer) noexcept
|
IsSilentBuffer(std::span<const ReplayGainAnalyzer::Frame> buffer) noexcept
|
||||||
{
|
{
|
||||||
return std::all_of(buffer.begin(), buffer.end(), IsSilentFrame);
|
return std::all_of(buffer.begin(), buffer.end(), IsSilentFrame);
|
||||||
}
|
}
|
||||||
@ -261,20 +260,20 @@ ReplayGainAnalyzer::Butter::Filter(Frame *gcc_restrict samples,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ReplayGainAnalyzer::Process(ConstBuffer<Frame> src) noexcept
|
ReplayGainAnalyzer::Process(std::span<const Frame> src) noexcept
|
||||||
{
|
{
|
||||||
assert(!src.empty());
|
assert(!src.empty());
|
||||||
|
|
||||||
float new_peak = FindPeak(src.front().data(),
|
float new_peak = FindPeak(src.front().data(),
|
||||||
src.size * src.front().size());
|
src.size() * src.front().size());
|
||||||
if (new_peak > peak)
|
if (new_peak > peak)
|
||||||
peak = new_peak;
|
peak = new_peak;
|
||||||
|
|
||||||
Frame *tmp = buffer.GetT<Frame>(src.size);
|
Frame *tmp = buffer.GetT<Frame>(src.size());
|
||||||
yule.Filter(src.data, tmp, src.size);
|
yule.Filter(src.data(), tmp, src.size());
|
||||||
butter.Filter(tmp, src.size);
|
butter.Filter(tmp, src.size());
|
||||||
|
|
||||||
const long level = std::lrint(std::floor(STEPS_PER_DB * CalcStereoRMS({tmp, src.size})));
|
const long level = std::lrint(std::floor(STEPS_PER_DB * CalcStereoRMS({tmp, src.size()})));
|
||||||
const std::size_t level_index = std::clamp(level, 0L, (long)histogram.size() - 1L);
|
const std::size_t level_index = std::clamp(level, 0L, (long)histogram.size() - 1L);
|
||||||
histogram[level_index]++;
|
histogram[level_index]++;
|
||||||
}
|
}
|
||||||
@ -318,37 +317,37 @@ ReplayGainAnalyzer::GetGain() const noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WindowReplayGainAnalyzer::CopyToBuffer(ConstBuffer<Frame> src) noexcept
|
WindowReplayGainAnalyzer::CopyToBuffer(std::span<const Frame> src) noexcept
|
||||||
{
|
{
|
||||||
std::copy(src.begin(), src.end(),
|
std::copy(src.begin(), src.end(),
|
||||||
window_buffer.data() + window_fill);
|
window_buffer.data() + window_fill);
|
||||||
window_fill += src.size;
|
window_fill += src.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WindowReplayGainAnalyzer::Process(ConstBuffer<Frame> src) noexcept
|
WindowReplayGainAnalyzer::Process(std::span<const Frame> src) noexcept
|
||||||
{
|
{
|
||||||
assert(window_fill < WINDOW_FRAMES);
|
assert(window_fill < WINDOW_FRAMES);
|
||||||
|
|
||||||
if (window_fill > 0) {
|
if (window_fill > 0) {
|
||||||
std::size_t window_space = WINDOW_FRAMES - window_fill;
|
std::size_t window_space = WINDOW_FRAMES - window_fill;
|
||||||
|
|
||||||
if (src.size < window_space) {
|
if (src.size() < window_space) {
|
||||||
CopyToBuffer(src);
|
CopyToBuffer(src);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyToBuffer({src.data, window_space});
|
CopyToBuffer({src.data(), window_space});
|
||||||
Flush();
|
Flush();
|
||||||
|
|
||||||
src.skip_front(window_space);
|
src = src.subspan(window_space);
|
||||||
if (src.empty())
|
if (src.empty())
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (src.size >= WINDOW_FRAMES) {
|
while (src.size() >= WINDOW_FRAMES) {
|
||||||
ReplayGainAnalyzer::Process({src.data, WINDOW_FRAMES});
|
ReplayGainAnalyzer::Process({src.data(), WINDOW_FRAMES});
|
||||||
src.skip_front(WINDOW_FRAMES);
|
src = src.subspan(WINDOW_FRAMES);
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyToBuffer(src);
|
CopyToBuffer(src);
|
||||||
|
@ -29,8 +29,7 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <span>
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Analyze a 44.1 kHz / stereo / float32 audio stream and calculate
|
* Analyze a 44.1 kHz / stereo / float32 audio stream and calculate
|
||||||
@ -112,7 +111,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
ReplayGainAnalyzer() noexcept;
|
ReplayGainAnalyzer() noexcept;
|
||||||
|
|
||||||
void Process(ConstBuffer<Frame> src) noexcept;
|
void Process(std::span<const Frame> src) noexcept;
|
||||||
|
|
||||||
float GetPeak() const noexcept {
|
float GetPeak() const noexcept {
|
||||||
return peak;
|
return peak;
|
||||||
@ -133,10 +132,10 @@ class WindowReplayGainAnalyzer : public ReplayGainAnalyzer {
|
|||||||
std::size_t window_fill = 0;
|
std::size_t window_fill = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Process(ConstBuffer<Frame> src) noexcept;
|
void Process(std::span<const Frame> src) noexcept;
|
||||||
|
|
||||||
void Flush() noexcept;
|
void Flush() noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CopyToBuffer(ConstBuffer<Frame> src) noexcept;
|
void CopyToBuffer(std::span<const Frame> src) noexcept;
|
||||||
};
|
};
|
||||||
|
@ -20,9 +20,11 @@
|
|||||||
#ifndef MPD_PCM_RESAMPLER_HXX
|
#ifndef MPD_PCM_RESAMPLER_HXX
|
||||||
#define MPD_PCM_RESAMPLER_HXX
|
#define MPD_PCM_RESAMPLER_HXX
|
||||||
|
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
#include "util/Compiler.h"
|
#include "util/Compiler.h"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
struct AudioFormat;
|
struct AudioFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,14 +70,14 @@ public:
|
|||||||
* @return the destination buffer (will be invalidated by
|
* @return the destination buffer (will be invalidated by
|
||||||
* filter_close() or filter_filter())
|
* filter_close() or filter_filter())
|
||||||
*/
|
*/
|
||||||
virtual ConstBuffer<void> Resample(ConstBuffer<void> src) = 0;
|
virtual std::span<const std::byte> Resample(std::span<const std::byte> src) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush pending data and return it. This should be called
|
* Flush pending data and return it. This should be called
|
||||||
* repepatedly until it returns nullptr.
|
* repepatedly until it returns nullptr.
|
||||||
*/
|
*/
|
||||||
virtual ConstBuffer<void> Flush() {
|
virtual std::span<const std::byte> Flush() {
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,8 +25,8 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
class PcmBuffer;
|
class PcmBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,33 +65,33 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConstBuffer<T> Complete(ConstBuffer<T> &src) noexcept {
|
std::span<const T> Complete(std::span<const T> &src) noexcept {
|
||||||
assert(audio_valid_channel_count(GetChannelCount()));
|
assert(audio_valid_channel_count(GetChannelCount()));
|
||||||
assert(src.size % GetChannelCount() == 0);
|
assert(src.size() % GetChannelCount() == 0);
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return nullptr;
|
return {};
|
||||||
|
|
||||||
size_t missing = capacity - size;
|
size_t missing = capacity - size;
|
||||||
size_t n = std::min(missing, src.size);
|
size_t n = std::min(missing, src.size());
|
||||||
std::copy_n(src.begin(), n, &data[size]);
|
std::copy_n(src.begin(), n, &data[size]);
|
||||||
src.skip_front(n);
|
src = src.subspan(n);
|
||||||
size += n;
|
size += n;
|
||||||
|
|
||||||
if (size < capacity)
|
if (size < capacity)
|
||||||
return nullptr;
|
return {};
|
||||||
|
|
||||||
size = 0;
|
size = 0;
|
||||||
return {data, capacity};
|
return {data, capacity};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Append(ConstBuffer<T> src) noexcept {
|
void Append(std::span<const T> src) noexcept {
|
||||||
assert(audio_valid_channel_count(GetChannelCount()));
|
assert(audio_valid_channel_count(GetChannelCount()));
|
||||||
assert(src.size % GetChannelCount() == 0);
|
assert(src.size() % GetChannelCount() == 0);
|
||||||
assert(size + src.size < capacity);
|
assert(size + src.size() < capacity);
|
||||||
|
|
||||||
std::copy_n(src.begin(), src.size, &data[size]);
|
std::copy(src.begin(), src.end(), &data[size]);
|
||||||
size += src.size;
|
size += src.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -109,18 +109,18 @@ public:
|
|||||||
* may be empty
|
* may be empty
|
||||||
*/
|
*/
|
||||||
template<typename U, typename F>
|
template<typename U, typename F>
|
||||||
ConstBuffer<U> Process(PcmBuffer &buffer, ConstBuffer<T> src,
|
std::span<const U> Process(PcmBuffer &buffer, std::span<const T> src,
|
||||||
size_t dest_block_size,
|
size_t dest_block_size,
|
||||||
F &&f) {
|
F &&f) {
|
||||||
assert(dest_block_size % GetChannelCount() == 0);
|
assert(dest_block_size % GetChannelCount() == 0);
|
||||||
|
|
||||||
const auto previous_rest = Complete(src);
|
const auto previous_rest = Complete(src);
|
||||||
assert(previous_rest.size == 0 ||
|
assert(previous_rest.size() == 0 ||
|
||||||
previous_rest.size == capacity);
|
previous_rest.size() == capacity);
|
||||||
|
|
||||||
const size_t previous_rest_blocks = !previous_rest.empty();
|
const size_t previous_rest_blocks = !previous_rest.empty();
|
||||||
const size_t src_blocks = src.size / capacity;
|
const size_t src_blocks = src.size() / capacity;
|
||||||
const size_t next_rest_samples = src.size % capacity;
|
const size_t next_rest_samples = src.size() % capacity;
|
||||||
const size_t dest_blocks = previous_rest_blocks + src_blocks;
|
const size_t dest_blocks = previous_rest_blocks + src_blocks;
|
||||||
const size_t dest_samples = dest_blocks * dest_block_size;
|
const size_t dest_samples = dest_blocks * dest_block_size;
|
||||||
|
|
||||||
@ -128,14 +128,14 @@ public:
|
|||||||
auto dest = dest0;
|
auto dest = dest0;
|
||||||
|
|
||||||
if (!previous_rest.empty()) {
|
if (!previous_rest.empty()) {
|
||||||
f(dest, previous_rest.data, previous_rest_blocks);
|
f(dest, previous_rest.data(), previous_rest_blocks);
|
||||||
dest += dest_block_size;
|
dest += dest_block_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
f(dest, src.data, src_blocks);
|
f(dest, src.data(), src_blocks);
|
||||||
|
|
||||||
if (next_rest_samples > 0)
|
if (next_rest_samples > 0)
|
||||||
Append({src.data + src_blocks * capacity,
|
Append({src.data() + src_blocks * capacity,
|
||||||
next_rest_samples});
|
next_rest_samples});
|
||||||
|
|
||||||
return { dest0, dest_samples };
|
return { dest0, dest_samples };
|
||||||
|
@ -267,13 +267,13 @@ SoxrPcmResampler::Reset() noexcept
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
SoxrPcmResampler::Resample(ConstBuffer<void> src)
|
SoxrPcmResampler::Resample(std::span<const std::byte> src)
|
||||||
{
|
{
|
||||||
const size_t frame_size = channels * sizeof(float);
|
const size_t frame_size = channels * sizeof(float);
|
||||||
assert(src.size % frame_size == 0);
|
assert(src.size() % frame_size == 0);
|
||||||
|
|
||||||
const size_t n_frames = src.size / frame_size;
|
const size_t n_frames = src.size() / frame_size;
|
||||||
|
|
||||||
/* always round up: worst case output buffer size */
|
/* always round up: worst case output buffer size */
|
||||||
const size_t o_frames = size_t(n_frames * ratio) + 1;
|
const size_t o_frames = size_t(n_frames * ratio) + 1;
|
||||||
@ -281,15 +281,15 @@ SoxrPcmResampler::Resample(ConstBuffer<void> src)
|
|||||||
auto *output_buffer = (float *)buffer.Get(o_frames * frame_size);
|
auto *output_buffer = (float *)buffer.Get(o_frames * frame_size);
|
||||||
|
|
||||||
size_t i_done, o_done;
|
size_t i_done, o_done;
|
||||||
soxr_error_t e = soxr_process(soxr, src.data, n_frames, &i_done,
|
soxr_error_t e = soxr_process(soxr, src.data(), n_frames, &i_done,
|
||||||
output_buffer, o_frames, &o_done);
|
output_buffer, o_frames, &o_done);
|
||||||
if (e != nullptr)
|
if (e != nullptr)
|
||||||
throw FormatRuntimeError("soxr error: %s", e);
|
throw FormatRuntimeError("soxr error: %s", e);
|
||||||
|
|
||||||
return { output_buffer, o_done * frame_size };
|
return { (const std::byte *)output_buffer, o_done * frame_size };
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
SoxrPcmResampler::Flush()
|
SoxrPcmResampler::Flush()
|
||||||
{
|
{
|
||||||
const size_t frame_size = channels * sizeof(float);
|
const size_t frame_size = channels * sizeof(float);
|
||||||
@ -307,5 +307,5 @@ SoxrPcmResampler::Flush()
|
|||||||
/* flush complete */
|
/* flush complete */
|
||||||
output_buffer = nullptr;
|
output_buffer = nullptr;
|
||||||
|
|
||||||
return { output_buffer, o_done * frame_size };
|
return { (const std::byte *)output_buffer, o_done * frame_size };
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,8 @@ public:
|
|||||||
AudioFormat Open(AudioFormat &af, unsigned new_sample_rate) override;
|
AudioFormat Open(AudioFormat &af, unsigned new_sample_rate) override;
|
||||||
void Close() noexcept override;
|
void Close() noexcept override;
|
||||||
void Reset() noexcept override;
|
void Reset() noexcept override;
|
||||||
ConstBuffer<void> Resample(ConstBuffer<void> src) override;
|
std::span<const std::byte> Resample(std::span<const std::byte> src) override;
|
||||||
ConstBuffer<void> Flush() override;
|
std::span<const std::byte> Flush() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "Volume.hxx"
|
#include "Volume.hxx"
|
||||||
#include "Silence.hxx"
|
#include "Silence.hxx"
|
||||||
#include "Traits.hxx"
|
#include "Traits.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
#include "util/TransformN.hxx"
|
#include "util/TransformN.hxx"
|
||||||
|
|
||||||
@ -185,13 +184,13 @@ PcmVolume::Open(SampleFormat _format, bool allow_convert)
|
|||||||
return format = _format;
|
return format = _format;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstBuffer<void>
|
std::span<const std::byte>
|
||||||
PcmVolume::Apply(ConstBuffer<void> src) noexcept
|
PcmVolume::Apply(std::span<const std::byte> src) noexcept
|
||||||
{
|
{
|
||||||
if (volume == PCM_VOLUME_1 && !convert)
|
if (volume == PCM_VOLUME_1 && !convert)
|
||||||
return src;
|
return src;
|
||||||
|
|
||||||
size_t dest_size = src.size;
|
size_t dest_size = src.size();
|
||||||
if (convert) {
|
if (convert) {
|
||||||
assert(format == SampleFormat::S16);
|
assert(format == SampleFormat::S16);
|
||||||
|
|
||||||
@ -205,7 +204,7 @@ PcmVolume::Apply(ConstBuffer<void> src) noexcept
|
|||||||
/* optimized special case: 0% volume = memset(0) */
|
/* optimized special case: 0% volume = memset(0) */
|
||||||
PcmSilence(std::span{(std::byte *)data, dest_size},
|
PcmSilence(std::span{(std::byte *)data, dest_size},
|
||||||
format);
|
format);
|
||||||
return { data, dest_size };
|
return { (const std::byte *)data, dest_size };
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (format) {
|
switch (format) {
|
||||||
@ -215,42 +214,42 @@ PcmVolume::Apply(ConstBuffer<void> src) noexcept
|
|||||||
|
|
||||||
case SampleFormat::S8:
|
case SampleFormat::S8:
|
||||||
pcm_volume_change_8(dither, (int8_t *)data,
|
pcm_volume_change_8(dither, (int8_t *)data,
|
||||||
(const int8_t *)src.data,
|
(const int8_t *)src.data(),
|
||||||
src.size / sizeof(int8_t),
|
src.size() / sizeof(int8_t),
|
||||||
volume);
|
volume);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SampleFormat::S16:
|
case SampleFormat::S16:
|
||||||
if (convert)
|
if (convert)
|
||||||
PcmVolumeChange16to32((int32_t *)data,
|
PcmVolumeChange16to32((int32_t *)data,
|
||||||
(const int16_t *)src.data,
|
(const int16_t *)src.data(),
|
||||||
src.size / sizeof(int16_t),
|
src.size() / sizeof(int16_t),
|
||||||
volume);
|
volume);
|
||||||
else
|
else
|
||||||
pcm_volume_change_16(dither, (int16_t *)data,
|
pcm_volume_change_16(dither, (int16_t *)data,
|
||||||
(const int16_t *)src.data,
|
(const int16_t *)src.data(),
|
||||||
src.size / sizeof(int16_t),
|
src.size() / sizeof(int16_t),
|
||||||
volume);
|
volume);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SampleFormat::S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
pcm_volume_change_24(dither, (int32_t *)data,
|
pcm_volume_change_24(dither, (int32_t *)data,
|
||||||
(const int32_t *)src.data,
|
(const int32_t *)src.data(),
|
||||||
src.size / sizeof(int32_t),
|
src.size() / sizeof(int32_t),
|
||||||
volume);
|
volume);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SampleFormat::S32:
|
case SampleFormat::S32:
|
||||||
pcm_volume_change_32(dither, (int32_t *)data,
|
pcm_volume_change_32(dither, (int32_t *)data,
|
||||||
(const int32_t *)src.data,
|
(const int32_t *)src.data(),
|
||||||
src.size / sizeof(int32_t),
|
src.size() / sizeof(int32_t),
|
||||||
volume);
|
volume);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SampleFormat::FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
pcm_volume_change_float((float *)data,
|
pcm_volume_change_float((float *)data,
|
||||||
(const float *)src.data,
|
(const float *)src.data(),
|
||||||
src.size / sizeof(float),
|
src.size() / sizeof(float),
|
||||||
pcm_volume_to_float(volume));
|
pcm_volume_to_float(volume));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -259,5 +258,5 @@ PcmVolume::Apply(ConstBuffer<void> src) noexcept
|
|||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { data, dest_size };
|
return { (const std::byte *)data, dest_size };
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,13 @@
|
|||||||
#include "Buffer.hxx"
|
#include "Buffer.hxx"
|
||||||
#include "Dither.hxx"
|
#include "Dither.hxx"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<typename T> struct ConstBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of fractional bits for a fixed-point volume value.
|
* Number of fractional bits for a fixed-point volume value.
|
||||||
*/
|
*/
|
||||||
@ -121,7 +122,7 @@ public:
|
|||||||
* Apply the volume level.
|
* Apply the volume level.
|
||||||
*/
|
*/
|
||||||
[[gnu::pure]]
|
[[gnu::pure]]
|
||||||
ConstBuffer<void> Apply(ConstBuffer<void> src) noexcept;
|
std::span<const std::byte> Apply(std::span<const std::byte> src) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "ReadFrames.hxx"
|
#include "ReadFrames.hxx"
|
||||||
#include "pcm/MixRampAnalyzer.hxx"
|
#include "pcm/MixRampAnalyzer.hxx"
|
||||||
#include "io/FileDescriptor.hxx"
|
#include "io/FileDescriptor.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
#include "util/PrintException.hxx"
|
#include "util/PrintException.hxx"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "pcm/ReplayGainAnalyzer.hxx"
|
#include "pcm/ReplayGainAnalyzer.hxx"
|
||||||
#include "io/FileDescriptor.hxx"
|
#include "io/FileDescriptor.hxx"
|
||||||
#include "system/Error.hxx"
|
#include "system/Error.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
#include "util/PrintException.hxx"
|
#include "util/PrintException.hxx"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include "fs/Path.hxx"
|
#include "fs/Path.hxx"
|
||||||
#include "fs/NarrowPath.hxx"
|
#include "fs/NarrowPath.hxx"
|
||||||
#include "io/FileDescriptor.hxx"
|
#include "io/FileDescriptor.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
#include "util/StaticFifoBuffer.hxx"
|
#include "util/StaticFifoBuffer.hxx"
|
||||||
#include "util/OptionDef.hxx"
|
#include "util/OptionDef.hxx"
|
||||||
#include "util/OptionParser.hxx"
|
#include "util/OptionParser.hxx"
|
||||||
@ -132,16 +131,16 @@ RunConvert(PcmConvert &convert, size_t in_frame_size,
|
|||||||
|
|
||||||
buffer.Consume(src.size());
|
buffer.Consume(src.size());
|
||||||
|
|
||||||
auto output = convert.Convert({src.data(), src.size()});
|
auto output = convert.Convert(src);
|
||||||
out_fd.FullWrite(output.data, output.size);
|
out_fd.FullWrite(output.data(), output.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto output = convert.Flush();
|
auto output = convert.Flush();
|
||||||
if (output.IsNull())
|
if (output.data() == nullptr)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
out_fd.FullWrite(output.data, output.size);
|
out_fd.FullWrite(output.data(), output.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#include "pcm/Volume.hxx"
|
#include "pcm/Volume.hxx"
|
||||||
#include "pcm/AudioParser.hxx"
|
#include "pcm/AudioParser.hxx"
|
||||||
#include "pcm/AudioFormat.hxx"
|
#include "pcm/AudioFormat.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
#include "util/PrintException.hxx"
|
#include "util/PrintException.hxx"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -37,7 +36,7 @@
|
|||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
try {
|
try {
|
||||||
static char buffer[4096];
|
static std::byte buffer[4096];
|
||||||
ssize_t nbytes;
|
ssize_t nbytes;
|
||||||
|
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
@ -58,7 +57,7 @@ try {
|
|||||||
|
|
||||||
while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) {
|
while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) {
|
||||||
auto dest = pv.Apply({buffer, size_t(nbytes)});
|
auto dest = pv.Apply({buffer, size_t(nbytes)});
|
||||||
[[maybe_unused]] ssize_t ignored = write(1, dest.data, dest.size);
|
[[maybe_unused]] ssize_t ignored = write(1, dest.data(), dest.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
pv.Close();
|
pv.Close();
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "test_pcm_util.hxx"
|
#include "test_pcm_util.hxx"
|
||||||
#include "pcm/PcmChannels.hxx"
|
#include "pcm/PcmChannels.hxx"
|
||||||
#include "pcm/Buffer.hxx"
|
#include "pcm/Buffer.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
@ -33,18 +32,18 @@ TEST(PcmTest, Channels16)
|
|||||||
|
|
||||||
/* stereo to mono */
|
/* stereo to mono */
|
||||||
|
|
||||||
auto dest = pcm_convert_channels_16(buffer, 1, 2, { src, N * 2 });
|
auto dest = pcm_convert_channels_16(buffer, 1, 2, src);
|
||||||
EXPECT_FALSE(dest.IsNull());
|
EXPECT_NE(dest.data(), nullptr);
|
||||||
EXPECT_EQ(N, dest.size);
|
EXPECT_EQ(N, dest.size());
|
||||||
for (unsigned i = 0; i < N; ++i)
|
for (unsigned i = 0; i < N; ++i)
|
||||||
EXPECT_EQ(int16_t((src[i * 2] + src[i * 2 + 1]) / 2),
|
EXPECT_EQ(int16_t((src[i * 2] + src[i * 2 + 1]) / 2),
|
||||||
dest[i]);
|
dest[i]);
|
||||||
|
|
||||||
/* mono to stereo */
|
/* mono to stereo */
|
||||||
|
|
||||||
dest = pcm_convert_channels_16(buffer, 2, 1, { src, N * 2 });
|
dest = pcm_convert_channels_16(buffer, 2, 1, src);
|
||||||
EXPECT_FALSE(dest.IsNull());
|
EXPECT_NE(dest.data(), nullptr);
|
||||||
EXPECT_EQ(N * 4, dest.size);
|
EXPECT_EQ(N * 4, dest.size());
|
||||||
for (unsigned i = 0; i < N; ++i) {
|
for (unsigned i = 0; i < N; ++i) {
|
||||||
EXPECT_EQ(src[i], dest[i * 2]);
|
EXPECT_EQ(src[i], dest[i * 2]);
|
||||||
EXPECT_EQ(src[i], dest[i * 2 + 1]);
|
EXPECT_EQ(src[i], dest[i * 2 + 1]);
|
||||||
@ -52,9 +51,9 @@ TEST(PcmTest, Channels16)
|
|||||||
|
|
||||||
/* stereo to 5.1 */
|
/* stereo to 5.1 */
|
||||||
|
|
||||||
dest = pcm_convert_channels_16(buffer, 6, 2, { src, N * 2 });
|
dest = pcm_convert_channels_16(buffer, 6, 2, src);
|
||||||
EXPECT_FALSE(dest.IsNull());
|
EXPECT_NE(dest.data(), nullptr);
|
||||||
EXPECT_EQ(N * 6, dest.size);
|
EXPECT_EQ(N * 6, dest.size());
|
||||||
constexpr int16_t silence = 0;
|
constexpr int16_t silence = 0;
|
||||||
for (unsigned i = 0; i < N; ++i) {
|
for (unsigned i = 0; i < N; ++i) {
|
||||||
EXPECT_EQ(src[i * 2], dest[i * 6]);
|
EXPECT_EQ(src[i * 2], dest[i * 6]);
|
||||||
@ -75,18 +74,18 @@ TEST(PcmTest, Channels32)
|
|||||||
|
|
||||||
/* stereo to mono */
|
/* stereo to mono */
|
||||||
|
|
||||||
auto dest = pcm_convert_channels_32(buffer, 1, 2, { src, N * 2 });
|
auto dest = pcm_convert_channels_32(buffer, 1, 2, src);
|
||||||
EXPECT_FALSE(dest.IsNull());
|
EXPECT_NE(dest.data(), nullptr);
|
||||||
EXPECT_EQ(N, dest.size);
|
EXPECT_EQ(N, dest.size());
|
||||||
for (unsigned i = 0; i < N; ++i)
|
for (unsigned i = 0; i < N; ++i)
|
||||||
EXPECT_EQ(int32_t(((int64_t)src[i * 2] + (int64_t)src[i * 2 + 1]) / 2),
|
EXPECT_EQ(int32_t(((int64_t)src[i * 2] + (int64_t)src[i * 2 + 1]) / 2),
|
||||||
dest[i]);
|
dest[i]);
|
||||||
|
|
||||||
/* mono to stereo */
|
/* mono to stereo */
|
||||||
|
|
||||||
dest = pcm_convert_channels_32(buffer, 2, 1, { src, N * 2 });
|
dest = pcm_convert_channels_32(buffer, 2, 1, src);
|
||||||
EXPECT_FALSE(dest.IsNull());
|
EXPECT_NE(dest.data(), nullptr);
|
||||||
EXPECT_EQ(N * 4, dest.size);
|
EXPECT_EQ(N * 4, dest.size());
|
||||||
for (unsigned i = 0; i < N; ++i) {
|
for (unsigned i = 0; i < N; ++i) {
|
||||||
EXPECT_EQ(src[i], dest[i * 2]);
|
EXPECT_EQ(src[i], dest[i * 2]);
|
||||||
EXPECT_EQ(src[i], dest[i * 2 + 1]);
|
EXPECT_EQ(src[i], dest[i * 2 + 1]);
|
||||||
@ -94,9 +93,9 @@ TEST(PcmTest, Channels32)
|
|||||||
|
|
||||||
/* stereo to 5.1 */
|
/* stereo to 5.1 */
|
||||||
|
|
||||||
dest = pcm_convert_channels_32(buffer, 6, 2, { src, N * 2 });
|
dest = pcm_convert_channels_32(buffer, 6, 2, src);
|
||||||
EXPECT_FALSE(dest.IsNull());
|
EXPECT_NE(dest.data(), nullptr);
|
||||||
EXPECT_EQ(N * 6, dest.size);
|
EXPECT_EQ(N * 6, dest.size());
|
||||||
constexpr int32_t silence = 0;
|
constexpr int32_t silence = 0;
|
||||||
for (unsigned i = 0; i < N; ++i) {
|
for (unsigned i = 0; i < N; ++i) {
|
||||||
EXPECT_EQ(src[i * 2], dest[i * 6]);
|
EXPECT_EQ(src[i * 2], dest[i * 6]);
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
#include "pcm/Export.hxx"
|
#include "pcm/Export.hxx"
|
||||||
#include "pcm/Traits.hxx"
|
#include "pcm/Traits.hxx"
|
||||||
#include "util/ByteOrder.hxx"
|
#include "util/ByteOrder.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
@ -46,14 +45,14 @@ TEST(PcmTest, ExportShift8)
|
|||||||
EXPECT_EQ(e.GetInputBlockSize(), 8u);
|
EXPECT_EQ(e.GetInputBlockSize(), 8u);
|
||||||
EXPECT_EQ(e.GetOutputBlockSize(), 8u);
|
EXPECT_EQ(e.GetOutputBlockSize(), 8u);
|
||||||
|
|
||||||
auto dest = e.Export({src, sizeof(src)});
|
auto dest = e.Export(std::as_bytes(std::span{src}));
|
||||||
EXPECT_EQ(sizeof(expected), dest.size);
|
EXPECT_EQ(sizeof(expected), dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, expected, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), expected, dest.size()) == 0);
|
||||||
|
|
||||||
const auto silence = e.GetSilence();
|
const auto silence = e.GetSilence();
|
||||||
constexpr uint8_t expected_silence[8]{};
|
constexpr uint8_t expected_silence[8]{};
|
||||||
EXPECT_EQ(silence.size, sizeof(expected_silence));
|
EXPECT_EQ(silence.size(), sizeof(expected_silence));
|
||||||
EXPECT_EQ(memcmp(silence.data, expected_silence,
|
EXPECT_EQ(memcmp(silence.data(), expected_silence,
|
||||||
sizeof(expected_silence)), 0);
|
sizeof(expected_silence)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,14 +94,14 @@ TEST(PcmTest, ExportPack24)
|
|||||||
EXPECT_EQ(e.GetInputBlockSize(), 8u);
|
EXPECT_EQ(e.GetInputBlockSize(), 8u);
|
||||||
EXPECT_EQ(e.GetOutputBlockSize(), 6u);
|
EXPECT_EQ(e.GetOutputBlockSize(), 6u);
|
||||||
|
|
||||||
auto dest = e.Export({src, sizeof(src)});
|
auto dest = e.Export(std::as_bytes(std::span{src}));
|
||||||
EXPECT_EQ(expected_size, dest.size);
|
EXPECT_EQ(expected_size, dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, expected, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), expected, dest.size()) == 0);
|
||||||
|
|
||||||
const auto silence = e.GetSilence();
|
const auto silence = e.GetSilence();
|
||||||
constexpr uint8_t expected_silence[6]{};
|
constexpr uint8_t expected_silence[6]{};
|
||||||
EXPECT_EQ(silence.size, sizeof(expected_silence));
|
EXPECT_EQ(silence.size(), sizeof(expected_silence));
|
||||||
EXPECT_EQ(memcmp(silence.data, expected_silence,
|
EXPECT_EQ(memcmp(silence.data(), expected_silence,
|
||||||
sizeof(expected_silence)), 0);
|
sizeof(expected_silence)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,9 +133,9 @@ TEST(PcmTest, ExportReverseEndian)
|
|||||||
EXPECT_EQ(e.GetInputBlockSize(), 2u);
|
EXPECT_EQ(e.GetInputBlockSize(), 2u);
|
||||||
EXPECT_EQ(e.GetOutputBlockSize(), 2u);
|
EXPECT_EQ(e.GetOutputBlockSize(), 2u);
|
||||||
|
|
||||||
auto dest = e.Export({src, sizeof(src)});
|
auto dest = e.Export(std::as_bytes(std::span{src}));
|
||||||
EXPECT_EQ(sizeof(src), dest.size);
|
EXPECT_EQ(sizeof(src), dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, src, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), src, dest.size()) == 0);
|
||||||
|
|
||||||
e.Open(SampleFormat::S16, 2, params);
|
e.Open(SampleFormat::S16, 2, params);
|
||||||
|
|
||||||
@ -145,9 +144,9 @@ TEST(PcmTest, ExportReverseEndian)
|
|||||||
EXPECT_EQ(e.GetInputBlockSize(), 4u);
|
EXPECT_EQ(e.GetInputBlockSize(), 4u);
|
||||||
EXPECT_EQ(e.GetOutputBlockSize(), 4u);
|
EXPECT_EQ(e.GetOutputBlockSize(), 4u);
|
||||||
|
|
||||||
dest = e.Export({src, sizeof(src)});
|
dest = e.Export(std::as_bytes(std::span{src}));
|
||||||
EXPECT_EQ(sizeof(expected2), dest.size);
|
EXPECT_EQ(sizeof(expected2), dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, expected2, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), expected2, dest.size()) == 0);
|
||||||
|
|
||||||
e.Open(SampleFormat::S32, 2, params);
|
e.Open(SampleFormat::S32, 2, params);
|
||||||
|
|
||||||
@ -156,14 +155,14 @@ TEST(PcmTest, ExportReverseEndian)
|
|||||||
EXPECT_EQ(e.GetInputBlockSize(), 8u);
|
EXPECT_EQ(e.GetInputBlockSize(), 8u);
|
||||||
EXPECT_EQ(e.GetOutputBlockSize(), 8u);
|
EXPECT_EQ(e.GetOutputBlockSize(), 8u);
|
||||||
|
|
||||||
dest = e.Export({src, sizeof(src)});
|
dest = e.Export(std::as_bytes(std::span{src}));
|
||||||
EXPECT_EQ(sizeof(expected4), dest.size);
|
EXPECT_EQ(sizeof(expected4), dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, expected4, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), expected4, dest.size()) == 0);
|
||||||
|
|
||||||
const auto silence = e.GetSilence();
|
const auto silence = e.GetSilence();
|
||||||
constexpr uint8_t expected_silence[8]{};
|
constexpr uint8_t expected_silence[8]{};
|
||||||
EXPECT_EQ(silence.size, sizeof(expected_silence));
|
EXPECT_EQ(silence.size(), sizeof(expected_silence));
|
||||||
EXPECT_EQ(memcmp(silence.data, expected_silence,
|
EXPECT_EQ(memcmp(silence.data(), expected_silence,
|
||||||
sizeof(expected_silence)), 0);
|
sizeof(expected_silence)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,33 +198,33 @@ TEST(PcmTest, ExportDsdU16)
|
|||||||
EXPECT_EQ(e.GetInputBlockSize(), 4u);
|
EXPECT_EQ(e.GetInputBlockSize(), 4u);
|
||||||
EXPECT_EQ(e.GetOutputBlockSize(), 4u);
|
EXPECT_EQ(e.GetOutputBlockSize(), 4u);
|
||||||
|
|
||||||
auto dest = e.Export({src, sizeof(src)});
|
auto dest = e.Export(std::as_bytes(std::span{src}));
|
||||||
EXPECT_EQ(sizeof(expected), dest.size);
|
EXPECT_EQ(sizeof(expected), dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, expected, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), expected, dest.size()) == 0);
|
||||||
|
|
||||||
/* no output, 2/4 remains */
|
/* no output, 2/4 remains */
|
||||||
static constexpr uint8_t src2[] = { 0x11, 0x22 };
|
static constexpr uint8_t src2[] = { 0x11, 0x22 };
|
||||||
dest = e.Export({src2, sizeof(src2)});
|
dest = e.Export(std::as_bytes(std::span{src2}));
|
||||||
EXPECT_TRUE(dest.empty());
|
EXPECT_TRUE(dest.empty());
|
||||||
|
|
||||||
/* one full frame and 2/4 remains */
|
/* one full frame and 2/4 remains */
|
||||||
static constexpr uint8_t src3[] = { 0x33, 0x44, 0x55, 0x66 };
|
static constexpr uint8_t src3[] = { 0x33, 0x44, 0x55, 0x66 };
|
||||||
static constexpr uint16_t expected3[] = { 0x1133, 0x2244 };
|
static constexpr uint16_t expected3[] = { 0x1133, 0x2244 };
|
||||||
dest = e.Export({src3, sizeof(src3)});
|
dest = e.Export(std::as_bytes(std::span{src3}));
|
||||||
EXPECT_EQ(sizeof(expected3), dest.size);
|
EXPECT_EQ(sizeof(expected3), dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, expected3, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), expected3, dest.size()) == 0);
|
||||||
|
|
||||||
/* two full frames and 2/4 remains again */
|
/* two full frames and 2/4 remains again */
|
||||||
static constexpr uint8_t src4[] = { 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee };
|
static constexpr uint8_t src4[] = { 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee };
|
||||||
static constexpr uint16_t expected4[] = { 0x5577, 0x6688, 0x99bb, 0xaacc };
|
static constexpr uint16_t expected4[] = { 0x5577, 0x6688, 0x99bb, 0xaacc };
|
||||||
dest = e.Export({src4, sizeof(src4)});
|
dest = e.Export(std::as_bytes(std::span{src4}));
|
||||||
EXPECT_EQ(sizeof(expected4), dest.size);
|
EXPECT_EQ(sizeof(expected4), dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, expected4, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), expected4, dest.size()) == 0);
|
||||||
|
|
||||||
const auto silence = e.GetSilence();
|
const auto silence = e.GetSilence();
|
||||||
constexpr uint8_t expected_silence[]{0x69, 0x69, 0x69, 0x69};
|
constexpr uint8_t expected_silence[]{0x69, 0x69, 0x69, 0x69};
|
||||||
EXPECT_EQ(silence.size, sizeof(expected_silence));
|
EXPECT_EQ(silence.size(), sizeof(expected_silence));
|
||||||
EXPECT_EQ(memcmp(silence.data, expected_silence,
|
EXPECT_EQ(memcmp(silence.data(), expected_silence,
|
||||||
sizeof(expected_silence)), 0);
|
sizeof(expected_silence)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,33 +258,33 @@ TEST(PcmTest, ExportDsdU32)
|
|||||||
EXPECT_EQ(e.GetInputBlockSize(), 8u);
|
EXPECT_EQ(e.GetInputBlockSize(), 8u);
|
||||||
EXPECT_EQ(e.GetOutputBlockSize(), 8u);
|
EXPECT_EQ(e.GetOutputBlockSize(), 8u);
|
||||||
|
|
||||||
auto dest = e.Export({src, sizeof(src)});
|
auto dest = e.Export(std::as_bytes(std::span{src}));
|
||||||
EXPECT_EQ(sizeof(expected), dest.size);
|
EXPECT_EQ(sizeof(expected), dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, expected, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), expected, dest.size()) == 0);
|
||||||
|
|
||||||
/* no output, 4/8 remains */
|
/* no output, 4/8 remains */
|
||||||
static constexpr uint8_t src2[] = { 0x11, 0x22, 0x33, 0x44 };
|
static constexpr uint8_t src2[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||||
dest = e.Export({src2, sizeof(src2)});
|
dest = e.Export(std::as_bytes(std::span{src2}));
|
||||||
EXPECT_TRUE(dest.empty());
|
EXPECT_TRUE(dest.empty());
|
||||||
|
|
||||||
/* one full frame and 4/8 remains */
|
/* one full frame and 4/8 remains */
|
||||||
static constexpr uint8_t src3[] = { 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc };
|
static constexpr uint8_t src3[] = { 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc };
|
||||||
static constexpr uint32_t expected3[] = { 0x11335577, 0x22446688 };
|
static constexpr uint32_t expected3[] = { 0x11335577, 0x22446688 };
|
||||||
dest = e.Export({src3, sizeof(src3)});
|
dest = e.Export(std::as_bytes(std::span{src3}));
|
||||||
EXPECT_EQ(sizeof(expected3), dest.size);
|
EXPECT_EQ(sizeof(expected3), dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, expected3, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), expected3, dest.size()) == 0);
|
||||||
|
|
||||||
/* two full frames and 2/4 remains again */
|
/* two full frames and 2/4 remains again */
|
||||||
static constexpr uint8_t src4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
|
static constexpr uint8_t src4[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
|
||||||
static constexpr uint32_t expected4[] = { 0x99bb0103, 0xaacc0204 };
|
static constexpr uint32_t expected4[] = { 0x99bb0103, 0xaacc0204 };
|
||||||
dest = e.Export({src4, sizeof(src4)});
|
dest = e.Export(std::as_bytes(std::span{src4}));
|
||||||
EXPECT_EQ(sizeof(expected4), dest.size);
|
EXPECT_EQ(sizeof(expected4), dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, expected4, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), expected4, dest.size()) == 0);
|
||||||
|
|
||||||
const auto silence = e.GetSilence();
|
const auto silence = e.GetSilence();
|
||||||
constexpr uint8_t expected_silence[]{0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69};
|
constexpr uint8_t expected_silence[]{0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69};
|
||||||
EXPECT_EQ(silence.size, sizeof(expected_silence));
|
EXPECT_EQ(silence.size(), sizeof(expected_silence));
|
||||||
EXPECT_EQ(memcmp(silence.data, expected_silence,
|
EXPECT_EQ(memcmp(silence.data(), expected_silence,
|
||||||
sizeof(expected_silence)), 0);
|
sizeof(expected_silence)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,43 +316,43 @@ TEST(PcmTest, ExportDop)
|
|||||||
EXPECT_EQ(e.GetInputBlockSize(), 8u);
|
EXPECT_EQ(e.GetInputBlockSize(), 8u);
|
||||||
EXPECT_EQ(e.GetOutputBlockSize(), 16u);
|
EXPECT_EQ(e.GetOutputBlockSize(), 16u);
|
||||||
|
|
||||||
auto dest = e.Export({src, sizeof(src)});
|
auto dest = e.Export(std::as_bytes(std::span{src}));
|
||||||
EXPECT_EQ(sizeof(expected), dest.size);
|
EXPECT_EQ(sizeof(expected), dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, expected, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), expected, dest.size()) == 0);
|
||||||
|
|
||||||
/* not enough data: 2/8 */
|
/* not enough data: 2/8 */
|
||||||
static constexpr uint8_t src2[] = { 0x12, 0x34 };
|
static constexpr uint8_t src2[] = { 0x12, 0x34 };
|
||||||
dest = e.Export({src2, sizeof(src2)});
|
dest = e.Export(std::as_bytes(std::span{src2}));
|
||||||
ASSERT_EQ(dest.size, 0u);
|
ASSERT_EQ(dest.size(), 0u);
|
||||||
|
|
||||||
/* not enough data: 6/8 */
|
/* not enough data: 6/8 */
|
||||||
static constexpr uint8_t src3[] = { 0x56, 0x78, 0x9a, 0xbc };
|
static constexpr uint8_t src3[] = { 0x56, 0x78, 0x9a, 0xbc };
|
||||||
dest = e.Export({src3, sizeof(src3)});
|
dest = e.Export(std::as_bytes(std::span{src3}));
|
||||||
ASSERT_EQ(dest.size, 0u);
|
ASSERT_EQ(dest.size(), 0u);
|
||||||
|
|
||||||
/* just enough data: 8/8 */
|
/* just enough data: 8/8 */
|
||||||
static constexpr uint8_t src4[] = { 0xde, 0xf0 };
|
static constexpr uint8_t src4[] = { 0xde, 0xf0 };
|
||||||
static constexpr uint32_t expected4[] = { 0xff051256, 0xff053478, 0xfffa9ade, 0xfffabcf0 };
|
static constexpr uint32_t expected4[] = { 0xff051256, 0xff053478, 0xfffa9ade, 0xfffabcf0 };
|
||||||
dest = e.Export({src4, sizeof(src4)});
|
dest = e.Export(std::as_bytes(std::span{src4}));
|
||||||
ASSERT_EQ(sizeof(expected4), dest.size);
|
ASSERT_EQ(sizeof(expected4), dest.size());
|
||||||
ASSERT_TRUE(memcmp(dest.data, expected4, dest.size) == 0);
|
ASSERT_TRUE(memcmp(dest.data(), expected4, dest.size()) == 0);
|
||||||
|
|
||||||
/* not enough data: 6/8 */
|
/* not enough data: 6/8 */
|
||||||
static constexpr uint8_t src5[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
|
static constexpr uint8_t src5[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
|
||||||
dest = e.Export({src5, sizeof(src5)});
|
dest = e.Export(std::as_bytes(std::span{src5}));
|
||||||
ASSERT_TRUE(dest.empty());
|
ASSERT_TRUE(dest.empty());
|
||||||
|
|
||||||
/* two quads returned, not enough data for more: 2/8 */
|
/* two quads returned, not enough data for more: 2/8 */
|
||||||
static constexpr uint8_t src6[] = { 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x10, 0x20 };
|
static constexpr uint8_t src6[] = { 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x10, 0x20 };
|
||||||
static constexpr uint32_t expected6[] = { 0xff051133, 0xff052244, 0xfffa5577, 0xfffa6688, 0xff0599bb, 0xff05aacc, 0xfffaddff, 0xfffaee00 };
|
static constexpr uint32_t expected6[] = { 0xff051133, 0xff052244, 0xfffa5577, 0xfffa6688, 0xff0599bb, 0xff05aacc, 0xfffaddff, 0xfffaee00 };
|
||||||
dest = e.Export({src6, sizeof(src6)});
|
dest = e.Export(std::as_bytes(std::span{src6}));
|
||||||
ASSERT_EQ(sizeof(expected6), dest.size);
|
ASSERT_EQ(sizeof(expected6), dest.size());
|
||||||
ASSERT_TRUE(memcmp(dest.data, expected6, dest.size) == 0);
|
ASSERT_TRUE(memcmp(dest.data(), expected6, dest.size()) == 0);
|
||||||
|
|
||||||
const auto silence = e.GetSilence();
|
const auto silence = e.GetSilence();
|
||||||
constexpr uint32_t expected_silence[]{0xff056969, 0xff056969, 0xfffa6969, 0xfffa6969};
|
constexpr uint32_t expected_silence[]{0xff056969, 0xff056969, 0xfffa6969, 0xfffa6969};
|
||||||
EXPECT_EQ(silence.size, sizeof(expected_silence));
|
EXPECT_EQ(silence.size(), sizeof(expected_silence));
|
||||||
EXPECT_EQ(memcmp(silence.data, expected_silence,
|
EXPECT_EQ(memcmp(silence.data(), expected_silence,
|
||||||
sizeof(expected_silence)), 0);
|
sizeof(expected_silence)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,9 +383,9 @@ TestAlsaChannelOrder51()
|
|||||||
PcmExport e;
|
PcmExport e;
|
||||||
e.Open(F, 6, params);
|
e.Open(F, 6, params);
|
||||||
|
|
||||||
auto dest = e.Export({src, sizeof(src)});
|
auto dest = e.Export(std::as_bytes(std::span{src}));
|
||||||
EXPECT_EQ(sizeof(expected), dest.size);
|
EXPECT_EQ(sizeof(expected), dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, expected, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), expected, dest.size()) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<SampleFormat F, class Traits=SampleTraits<F>>
|
template<SampleFormat F, class Traits=SampleTraits<F>>
|
||||||
@ -414,14 +413,14 @@ TestAlsaChannelOrder71()
|
|||||||
PcmExport e;
|
PcmExport e;
|
||||||
e.Open(F, 8, params);
|
e.Open(F, 8, params);
|
||||||
|
|
||||||
auto dest = e.Export({src, sizeof(src)});
|
auto dest = e.Export(std::as_bytes(std::span{src}));
|
||||||
EXPECT_EQ(sizeof(expected), dest.size);
|
EXPECT_EQ(sizeof(expected), dest.size());
|
||||||
EXPECT_TRUE(memcmp(dest.data, expected, dest.size) == 0);
|
EXPECT_TRUE(memcmp(dest.data(), expected, dest.size()) == 0);
|
||||||
|
|
||||||
const auto silence = e.GetSilence();
|
const auto silence = e.GetSilence();
|
||||||
constexpr value_type expected_silence[8]{};
|
constexpr value_type expected_silence[8]{};
|
||||||
EXPECT_EQ(silence.size, sizeof(expected_silence));
|
EXPECT_EQ(silence.size(), sizeof(expected_silence));
|
||||||
EXPECT_EQ(memcmp(silence.data, expected_silence,
|
EXPECT_EQ(memcmp(silence.data(), expected_silence,
|
||||||
sizeof(expected_silence)), 0);
|
sizeof(expected_silence)), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ TEST(PcmTest, Format8To16)
|
|||||||
|
|
||||||
PcmDither dither;
|
PcmDither dither;
|
||||||
auto d = pcm_convert_to_16(buffer, dither, SampleFormat::S8, src);
|
auto d = pcm_convert_to_16(buffer, dither, SampleFormat::S8, src);
|
||||||
EXPECT_EQ(N, d.size);
|
EXPECT_EQ(N, d.size());
|
||||||
|
|
||||||
for (size_t i = 0; i < N; ++i)
|
for (size_t i = 0; i < N; ++i)
|
||||||
EXPECT_EQ(int(src[i]), d[i] >> 8);
|
EXPECT_EQ(int(src[i]), d[i] >> 8);
|
||||||
@ -48,7 +48,7 @@ TEST(PcmTest, Format16To24)
|
|||||||
PcmBuffer buffer;
|
PcmBuffer buffer;
|
||||||
|
|
||||||
auto d = pcm_convert_to_24(buffer, SampleFormat::S16, src);
|
auto d = pcm_convert_to_24(buffer, SampleFormat::S16, src);
|
||||||
EXPECT_EQ(N, d.size);
|
EXPECT_EQ(N, d.size());
|
||||||
|
|
||||||
for (size_t i = 0; i < N; ++i)
|
for (size_t i = 0; i < N; ++i)
|
||||||
EXPECT_EQ(int(src[i]), d[i] >> 8);
|
EXPECT_EQ(int(src[i]), d[i] >> 8);
|
||||||
@ -62,7 +62,7 @@ TEST(PcmTest, Format16To32)
|
|||||||
PcmBuffer buffer;
|
PcmBuffer buffer;
|
||||||
|
|
||||||
auto d = pcm_convert_to_32(buffer, SampleFormat::S16, src);
|
auto d = pcm_convert_to_32(buffer, SampleFormat::S16, src);
|
||||||
EXPECT_EQ(N, d.size);
|
EXPECT_EQ(N, d.size());
|
||||||
|
|
||||||
for (size_t i = 0; i < N; ++i)
|
for (size_t i = 0; i < N; ++i)
|
||||||
EXPECT_EQ(int(src[i]), d[i] >> 16);
|
EXPECT_EQ(int(src[i]), d[i] >> 16);
|
||||||
@ -76,9 +76,9 @@ TEST(PcmTest, FormatFloat16)
|
|||||||
PcmBuffer buffer1, buffer2;
|
PcmBuffer buffer1, buffer2;
|
||||||
|
|
||||||
auto f = pcm_convert_to_float(buffer1, SampleFormat::S16, src);
|
auto f = pcm_convert_to_float(buffer1, SampleFormat::S16, src);
|
||||||
EXPECT_EQ(N, f.size);
|
EXPECT_EQ(N, f.size());
|
||||||
|
|
||||||
for (size_t i = 0; i != f.size; ++i) {
|
for (size_t i = 0; i != f.size(); ++i) {
|
||||||
EXPECT_GE(f[i], -1.f);
|
EXPECT_GE(f[i], -1.f);
|
||||||
EXPECT_LE(f[i], 1.f);
|
EXPECT_LE(f[i], 1.f);
|
||||||
}
|
}
|
||||||
@ -87,14 +87,14 @@ TEST(PcmTest, FormatFloat16)
|
|||||||
|
|
||||||
auto d = pcm_convert_to_16(buffer2, dither,
|
auto d = pcm_convert_to_16(buffer2, dither,
|
||||||
SampleFormat::FLOAT,
|
SampleFormat::FLOAT,
|
||||||
f.ToVoid());
|
std::as_bytes(f));
|
||||||
EXPECT_EQ(N, d.size);
|
EXPECT_EQ(N, d.size());
|
||||||
|
|
||||||
for (size_t i = 0; i < N; ++i)
|
for (size_t i = 0; i < N; ++i)
|
||||||
EXPECT_EQ(src[i], d[i]);
|
EXPECT_EQ(src[i], d[i]);
|
||||||
|
|
||||||
/* check if clamping works */
|
/* check if clamping works */
|
||||||
auto *writable = const_cast<float *>(f.data);
|
auto *writable = const_cast<float *>(f.data());
|
||||||
*writable++ = 1.01;
|
*writable++ = 1.01;
|
||||||
*writable++ = 10;
|
*writable++ = 10;
|
||||||
*writable++ = -1.01;
|
*writable++ = -1.01;
|
||||||
@ -102,8 +102,8 @@ TEST(PcmTest, FormatFloat16)
|
|||||||
|
|
||||||
d = pcm_convert_to_16(buffer2, dither,
|
d = pcm_convert_to_16(buffer2, dither,
|
||||||
SampleFormat::FLOAT,
|
SampleFormat::FLOAT,
|
||||||
f.ToVoid());
|
std::as_bytes(f));
|
||||||
EXPECT_EQ(N, d.size);
|
EXPECT_EQ(N, d.size());
|
||||||
|
|
||||||
EXPECT_EQ(32767, int(d[0]));
|
EXPECT_EQ(32767, int(d[0]));
|
||||||
EXPECT_EQ(32767, int(d[1]));
|
EXPECT_EQ(32767, int(d[1]));
|
||||||
@ -122,17 +122,17 @@ TEST(PcmTest, FormatFloat32)
|
|||||||
PcmBuffer buffer1, buffer2;
|
PcmBuffer buffer1, buffer2;
|
||||||
|
|
||||||
auto f = pcm_convert_to_float(buffer1, SampleFormat::S32, src);
|
auto f = pcm_convert_to_float(buffer1, SampleFormat::S32, src);
|
||||||
EXPECT_EQ(N, f.size);
|
EXPECT_EQ(N, f.size());
|
||||||
|
|
||||||
for (size_t i = 0; i != f.size; ++i) {
|
for (size_t i = 0; i != f.size(); ++i) {
|
||||||
EXPECT_GE(f[i], -1.f);
|
EXPECT_GE(f[i], -1.f);
|
||||||
EXPECT_LE(f[i], 1.f);
|
EXPECT_LE(f[i], 1.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto d = pcm_convert_to_32(buffer2,
|
auto d = pcm_convert_to_32(buffer2,
|
||||||
SampleFormat::FLOAT,
|
SampleFormat::FLOAT,
|
||||||
f.ToVoid());
|
std::as_bytes(f));
|
||||||
EXPECT_EQ(N, d.size);
|
EXPECT_EQ(N, d.size());
|
||||||
|
|
||||||
constexpr int error = 64;
|
constexpr int error = 64;
|
||||||
|
|
||||||
@ -140,7 +140,7 @@ TEST(PcmTest, FormatFloat32)
|
|||||||
EXPECT_NEAR(src[i], d[i], error);
|
EXPECT_NEAR(src[i], d[i], error);
|
||||||
|
|
||||||
/* check if clamping works */
|
/* check if clamping works */
|
||||||
auto *writable = const_cast<float *>(f.data);
|
auto *writable = const_cast<float *>(f.data());
|
||||||
*writable++ = 1.01;
|
*writable++ = 1.01;
|
||||||
*writable++ = 10;
|
*writable++ = 10;
|
||||||
*writable++ = -1.01;
|
*writable++ = -1.01;
|
||||||
@ -148,8 +148,8 @@ TEST(PcmTest, FormatFloat32)
|
|||||||
|
|
||||||
d = pcm_convert_to_32(buffer2,
|
d = pcm_convert_to_32(buffer2,
|
||||||
SampleFormat::FLOAT,
|
SampleFormat::FLOAT,
|
||||||
f.ToVoid());
|
std::as_bytes(f));
|
||||||
EXPECT_EQ(N, d.size);
|
EXPECT_EQ(N, d.size());
|
||||||
|
|
||||||
EXPECT_EQ(2147483647, int(d[0]));
|
EXPECT_EQ(2147483647, int(d[0]));
|
||||||
EXPECT_EQ(2147483647, int(d[1]));
|
EXPECT_EQ(2147483647, int(d[1]));
|
||||||
|
@ -35,8 +35,10 @@ TestInterleaveN()
|
|||||||
static constexpr size_t n_frames = std::size(src1);
|
static constexpr size_t n_frames = std::size(src1);
|
||||||
static constexpr unsigned channels = std::size(src_all);
|
static constexpr unsigned channels = std::size(src_all);
|
||||||
|
|
||||||
static const ConstBuffer<const void *> src((const void *const*)src_all,
|
static const std::span<const void *const> src{
|
||||||
channels);
|
(const void *const*)src_all,
|
||||||
|
channels,
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr T poison = T(0xdeadbeef);
|
static constexpr T poison = T(0xdeadbeef);
|
||||||
T dest[n_frames * channels + 1];
|
T dest[n_frames * channels + 1];
|
||||||
@ -77,8 +79,10 @@ TEST(PcmTest, Interleave24)
|
|||||||
static constexpr size_t n_frames = std::size(src1) / 3;
|
static constexpr size_t n_frames = std::size(src1) / 3;
|
||||||
static constexpr unsigned channels = std::size(src_all);
|
static constexpr unsigned channels = std::size(src_all);
|
||||||
|
|
||||||
static const ConstBuffer<const void *> src((const void *const*)src_all,
|
static const std::span<const void *const> src{
|
||||||
channels);
|
(const void *const*)src_all,
|
||||||
|
channels,
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr T poison = 0xff;
|
static constexpr T poison = 0xff;
|
||||||
T dest[n_frames * channels * 3 + 1];
|
T dest[n_frames * channels * 3 + 1];
|
||||||
|
@ -17,12 +17,11 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "util/ConstBuffer.hxx"
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <span>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -81,12 +80,12 @@ public:
|
|||||||
return begin();
|
return begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
operator ConstBuffer<T>() const {
|
operator std::span<const T>() const {
|
||||||
return { begin(), size() };
|
return { begin(), size() };
|
||||||
}
|
}
|
||||||
|
|
||||||
operator ConstBuffer<void>() const {
|
operator std::span<const std::byte>() const {
|
||||||
return { begin(), size() * sizeof(T) };
|
return { (const std::byte *)begin(), size() * sizeof(T) };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
#include "pcm/Volume.hxx"
|
#include "pcm/Volume.hxx"
|
||||||
#include "pcm/Traits.hxx"
|
#include "pcm/Traits.hxx"
|
||||||
#include "util/ConstBuffer.hxx"
|
#include "util/SpanCast.hxx"
|
||||||
#include "test_pcm_util.hxx"
|
#include "test_pcm_util.hxx"
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
@ -41,23 +41,23 @@ TestVolume(G g=G())
|
|||||||
constexpr size_t N = 509;
|
constexpr size_t N = 509;
|
||||||
static value_type zero[N];
|
static value_type zero[N];
|
||||||
const auto _src = TestDataBuffer<value_type, N>(g);
|
const auto _src = TestDataBuffer<value_type, N>(g);
|
||||||
const ConstBuffer<void> src(_src, sizeof(_src));
|
const std::span<const std::byte> src = _src;
|
||||||
|
|
||||||
pv.SetVolume(0);
|
pv.SetVolume(0);
|
||||||
auto dest = pv.Apply(src);
|
auto dest = pv.Apply(src);
|
||||||
EXPECT_EQ(src.size, dest.size);
|
EXPECT_EQ(src.size(), dest.size());
|
||||||
EXPECT_EQ(0, memcmp(dest.data, zero, sizeof(zero)));
|
EXPECT_EQ(0, memcmp(dest.data(), zero, sizeof(zero)));
|
||||||
|
|
||||||
pv.SetVolume(PCM_VOLUME_1);
|
pv.SetVolume(PCM_VOLUME_1);
|
||||||
dest = pv.Apply(src);
|
dest = pv.Apply(src);
|
||||||
EXPECT_EQ(src.size, dest.size);
|
EXPECT_EQ(src.size(), dest.size());
|
||||||
EXPECT_EQ(0, memcmp(dest.data, src.data, src.size));
|
EXPECT_EQ(0, memcmp(dest.data(), src.data(), src.size()));
|
||||||
|
|
||||||
pv.SetVolume(PCM_VOLUME_1 / 2);
|
pv.SetVolume(PCM_VOLUME_1 / 2);
|
||||||
dest = pv.Apply(src);
|
dest = pv.Apply(src);
|
||||||
EXPECT_EQ(src.size, dest.size);
|
EXPECT_EQ(src.size(), dest.size());
|
||||||
|
|
||||||
const auto _dest = ConstBuffer<value_type>::FromVoid(dest);
|
const auto _dest = FromBytesStrict<const value_type>(dest);
|
||||||
for (unsigned i = 0; i < N; ++i) {
|
for (unsigned i = 0; i < N; ++i) {
|
||||||
const auto expected = (_src[i] + 1) / 2;
|
const auto expected = (_src[i] + 1) / 2;
|
||||||
EXPECT_GE(_dest[i], expected - 4);
|
EXPECT_GE(_dest[i], expected - 4);
|
||||||
@ -89,27 +89,27 @@ TEST(PcmTest, Volume16to32)
|
|||||||
constexpr size_t N = 509;
|
constexpr size_t N = 509;
|
||||||
static value_type zero[N];
|
static value_type zero[N];
|
||||||
const auto _src = TestDataBuffer<value_type, N>(g);
|
const auto _src = TestDataBuffer<value_type, N>(g);
|
||||||
const ConstBuffer<void> src(_src, sizeof(_src));
|
const std::span<const std::byte> src = _src;
|
||||||
|
|
||||||
pv.SetVolume(0);
|
pv.SetVolume(0);
|
||||||
auto dest = pv.Apply(src);
|
auto dest = pv.Apply(src);
|
||||||
EXPECT_EQ(src.size * 2, dest.size);
|
EXPECT_EQ(src.size() * 2, dest.size());
|
||||||
EXPECT_EQ(0, memcmp(dest.data, zero, sizeof(zero)));
|
EXPECT_EQ(0, memcmp(dest.data(), zero, sizeof(zero)));
|
||||||
|
|
||||||
pv.SetVolume(PCM_VOLUME_1);
|
pv.SetVolume(PCM_VOLUME_1);
|
||||||
dest = pv.Apply(src);
|
dest = pv.Apply(src);
|
||||||
EXPECT_EQ(src.size * 2, dest.size);
|
EXPECT_EQ(src.size() * 2, dest.size());
|
||||||
auto s = ConstBuffer<int16_t>::FromVoid(src);
|
auto s = FromBytesStrict<const int16_t>(src);
|
||||||
auto d = ConstBuffer<int32_t>::FromVoid(dest);
|
auto d = FromBytesStrict<const int32_t>(dest);
|
||||||
for (size_t i = 0; i < N; ++i)
|
for (size_t i = 0; i < N; ++i)
|
||||||
EXPECT_EQ(d[i], s[i] << 8);
|
EXPECT_EQ(d[i], s[i] << 8);
|
||||||
|
|
||||||
pv.SetVolume(PCM_VOLUME_1 / 2);
|
pv.SetVolume(PCM_VOLUME_1 / 2);
|
||||||
dest = pv.Apply(src);
|
dest = pv.Apply(src);
|
||||||
EXPECT_EQ(src.size * 2, dest.size);
|
EXPECT_EQ(src.size() * 2, dest.size());
|
||||||
|
|
||||||
s = ConstBuffer<int16_t>::FromVoid(src);
|
s = FromBytesStrict<const int16_t>(src);
|
||||||
d = ConstBuffer<int32_t>::FromVoid(dest);
|
d = FromBytesStrict<const int32_t>(dest);
|
||||||
for (unsigned i = 0; i < N; ++i) {
|
for (unsigned i = 0; i < N; ++i) {
|
||||||
const int32_t expected = (s[i] << 8) / 2;
|
const int32_t expected = (s[i] << 8) / 2;
|
||||||
EXPECT_EQ(d[i], expected);
|
EXPECT_EQ(d[i], expected);
|
||||||
@ -136,23 +136,23 @@ TEST(PcmTest, VolumeFloat)
|
|||||||
constexpr size_t N = 509;
|
constexpr size_t N = 509;
|
||||||
static float zero[N];
|
static float zero[N];
|
||||||
const auto _src = TestDataBuffer<float, N>(RandomFloat());
|
const auto _src = TestDataBuffer<float, N>(RandomFloat());
|
||||||
const ConstBuffer<void> src(_src, sizeof(_src));
|
const std::span<const std::byte> src = _src;
|
||||||
|
|
||||||
pv.SetVolume(0);
|
pv.SetVolume(0);
|
||||||
auto dest = pv.Apply(src);
|
auto dest = pv.Apply(src);
|
||||||
EXPECT_EQ(src.size, dest.size);
|
EXPECT_EQ(src.size(), dest.size());
|
||||||
EXPECT_EQ(0, memcmp(dest.data, zero, sizeof(zero)));
|
EXPECT_EQ(0, memcmp(dest.data(), zero, sizeof(zero)));
|
||||||
|
|
||||||
pv.SetVolume(PCM_VOLUME_1);
|
pv.SetVolume(PCM_VOLUME_1);
|
||||||
dest = pv.Apply(src);
|
dest = pv.Apply(src);
|
||||||
EXPECT_EQ(src.size, dest.size);
|
EXPECT_EQ(src.size(), dest.size());
|
||||||
EXPECT_EQ(0, memcmp(dest.data, src.data, src.size));
|
EXPECT_EQ(0, memcmp(dest.data(), src.data(), src.size()));
|
||||||
|
|
||||||
pv.SetVolume(PCM_VOLUME_1 / 2);
|
pv.SetVolume(PCM_VOLUME_1 / 2);
|
||||||
dest = pv.Apply(src);
|
dest = pv.Apply(src);
|
||||||
EXPECT_EQ(src.size, dest.size);
|
EXPECT_EQ(src.size(), dest.size());
|
||||||
|
|
||||||
const auto _dest = ConstBuffer<float>::FromVoid(dest);
|
const auto _dest = FromBytesStrict<const float>(dest);
|
||||||
for (unsigned i = 0; i < N; ++i)
|
for (unsigned i = 0; i < N; ++i)
|
||||||
EXPECT_NEAR((double)_src[i] / 2., (double)_dest[i], 1.);
|
EXPECT_NEAR((double)_src[i] / 2., (double)_dest[i], 1.);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user