pcm/*: use std::span instead of ConstBuffer

This commit is contained in:
Max Kellermann 2022-07-04 15:27:03 +02:00
parent d89136b09c
commit 4ce1dae673
58 changed files with 572 additions and 595 deletions

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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);
} }

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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 {};
} }

View File

@ -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

View File

@ -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); });

View File

@ -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

View File

@ -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); });

View File

@ -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

View File

@ -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); });

View File

@ -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

View File

@ -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;

View File

@ -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()

View File

@ -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:

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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);
} }
} }

View File

@ -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);
} }

View File

@ -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)));
} }

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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 };
} }

View File

@ -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

View File

@ -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 {};
} }

View File

@ -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

View File

@ -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);

View File

@ -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;
}; };

View File

@ -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 {};
} }
}; };

View File

@ -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 };

View File

@ -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 };
} }

View File

@ -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

View File

@ -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 };
} }

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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());
} }
} }

View File

@ -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();

View File

@ -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]);

View File

@ -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);
} }

View File

@ -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]));

View File

@ -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];

View File

@ -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) };
} }
}; };

View File

@ -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.);