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