18#include <wavpack/wavpack.h>
33 WavpackContext* Context {
nullptr };
38 : Block {
std::move(block) }
40 WavpackConfig config = {};
42 config.num_channels = 1;
43 config.channel_mask = 0x4;
45 config.sample_rate = 48000;
48 config.bits_per_sample = config.bytes_per_sample * 8;
51 config.flags = CONFIG_FAST_FLAG;
53 Context = WavpackOpenFileOutput(WriteBlock,
this,
nullptr);
56 !WavpackSetConfiguration(
57 Context, &config, Block.
Block->GetSampleCount()) ||
58 !WavpackPackInit(Context))
60 WavpackCloseFile(Context);
67 if (Context !=
nullptr)
68 WavpackCloseFile(Context);
77 std::vector<std::remove_pointer_t<samplePtr>> sampleData;
78 sampleData.resize(dataSize);
80 const size_t samplesRead = Block.
Block->GetSamples(
86 CompressedData.reserve(sampleData.size() * 3 / 2);
90 constexpr size_t conversionSamplesCount = 4096;
92 const int16_t* int16Data =
reinterpret_cast<const int16_t*
>(sampleData.data());
93 std::vector<int32_t> buffer;
94 buffer.resize(conversionSamplesCount);
96 for (
size_t firstSample = 0; firstSample < samplesRead;
97 firstSample += conversionSamplesCount)
99 const auto samplesThisRun =
100 std::min(conversionSamplesCount, samplesRead - firstSample);
102 for (
size_t i = 0; i < samplesThisRun; ++i)
104 (
static_cast<int32_t
>(int16Data[firstSample + i]) * 65536) >>
107 WavpackPackSamples(Context, buffer.data(), samplesThisRun);
112 const void* data = sampleData.data();
114 Context,
static_cast<int32_t*
>(
const_cast<void*
>(data)),
120 return std::move(CompressedData);
123 void Feed(int32_t* data, int32_t count)
125 if (Context ==
nullptr)
128 WavpackPackSamples(Context, data, count);
133 if (Context ==
nullptr)
136 WavpackFlushSamples(Context);
138 const std::string formatString = std::to_string(
unsigned(Block.
Format));
139 WavpackAppendTagItem(
140 Context,
"FORMAT", formatString.data(), formatString.size());
142 const std::string blockIdString = std::to_string(Block.
Id);
143 WavpackAppendTagItem(
144 Context,
"BLOCK_ID", blockIdString.data(), blockIdString.size());
146 WavpackAppendTagItem(
147 Context,
"HASH", Block.
Hash.data(), Block.
Hash.size());
149 WavpackWriteTag(Context);
150 WavpackCloseFile(Context);
157 if (
id ==
nullptr || data ==
nullptr || length == 0)
162 auto start =
reinterpret_cast<uint8_t*
>(data);
163 auto end = start + length;
174 WavpackContext* Context {
nullptr };
177 const void* Data {
nullptr };
180 int64_t Offset { 0 };
183 uint32_t SamplesCount {};
185 uint8_t UngetcChar { 0 };
186 bool UngetcFlag {
false };
191 int64_t BlockId { -1 };
200 return Context !=
nullptr && SamplesCount > 0 &&
204 ((BlockId >= 0) || (BlockId < 0 && -BlockId == SamplesCount));
211 if (Data ==
nullptr ||
Size == 0)
216 Context = WavpackOpenFileInputEx64(
217 &raw_reader,
this,
nullptr, error, OPEN_DSD_AS_PCM | OPEN_TAGS, 0);
219 if (Context ==
nullptr)
222 Mode = WavpackGetMode(Context);
223 SamplesCount = WavpackGetNumSamples(Context);
225 const auto formatString = ReadTag(
"FORMAT");
228 formatString.c_str(), formatString.c_str() + formatString.size(),
230 if (result.ec == std::errc {})
233 auto blockIdString = ReadTag(
"BLOCK_ID");
235 blockIdString.c_str(), blockIdString.c_str() + blockIdString.size(),
241 if (Context ==
nullptr)
244 const auto tagLength = WavpackGetTagItem(Context, tagName,
nullptr, 0);
250 tag.resize(tagLength + 1);
251 WavpackGetTagItem(Context, tagName, tag.data(), tagLength + 1);
252 tag.resize(tagLength);
260 if (Context !=
nullptr)
261 WavpackCloseFile(Context);
269 Int32Buffer.resize(SamplesCount);
272 Int16Buffer.resize(SamplesCount);
274 FloatBuffer.resize(SamplesCount);
276 const auto samplesRead =
277 WavpackUnpackSamples(Context, Int32Buffer.data(), SamplesCount);
279 if (samplesRead != SamplesCount)
282 const bool floatSamples = (Mode & MODE_FLOAT) == MODE_FLOAT;
286 FloatBuffer.resize(SamplesCount);
288 FloatBuffer.data(), Int32Buffer.data(),
289 SamplesCount *
sizeof(
float));
293 const auto bytesPerSample = WavpackGetBytesPerSample(Context);
295 if (bytesPerSample == 1)
297 for (
size_t i = 0; i < SamplesCount; ++i)
298 Int16Buffer[i] =
static_cast<int16_t
>(Int32Buffer[i]) << 8;
300 else if (bytesPerSample == 2)
302 for (
size_t i = 0; i < SamplesCount; ++i)
303 Int16Buffer[i] =
static_cast<int16_t
>(Int32Buffer[i]);
319 uint8_t* outptr =
static_cast<uint8_t*
>(data);
328 const auto bytesToCopy =
329 std::min<int32_t>(bcount, importer->
Size - importer->
Offset);
332 outptr,
static_cast<const uint8_t*
>(importer->
Data) + importer->
Offset,
335 outptr += bytesToCopy;
336 bcount -= bytesToCopy;
338 importer->
Offset += bytesToCopy;
340 return static_cast<int32_t
>(outptr -
static_cast<uint8_t*
>(data));
355 return raw_set_pos_rel(
id, pos, SEEK_SET);
366 if (delta < 0 || delta > importer->
Size)
373 const auto newOffset = delta + importer->
Offset;
374 if (newOffset < 0 || newOffset > importer->
Size)
376 importer->
Offset += delta;
381 if (delta > 0 || -delta > importer->
Size)
416 WavpackStreamReader64 raw_reader { raw_read_bytes, raw_write_bytes,
417 raw_get_pos, raw_set_pos_abs,
418 raw_set_pos_rel, raw_push_back_byte,
419 raw_get_length, raw_can_seek,
420 nullptr, raw_close_stream };
426 return static_cast<float>(value) / std::numeric_limits<int16_t>::max();
431 return static_cast<float>(value) / ((1 << 23) - 1);
442 const auto samplesCount = data.size();
443 const auto sum256Count = (samplesCount + 255) / 256;
444 const auto sum64kCount = (samplesCount + 65535) / 65536;
451 for (
size_t i = 0; i < samplesCount; ++i)
455 blockStats.Min =
std::min(blockStats.Min, value);
456 blockStats.Max = std::max(blockStats.Max, value);
457 blockStats.RMS += value * value;
461 summary256.Min =
std::min(summary256.Min, value);
462 summary256.Max = std::max(summary256.Max, value);
463 summary256.RMS += value * value;
465 auto& summary64k = block.
Summary64k[i / 65536];
466 summary64k.Min =
std::min(summary64k.Min, value);
467 summary64k.Max = std::max(summary64k.Max, value);
468 summary64k.RMS += value * value;
473 auto samplesProcessed = 0;
476 const auto samplesToProcess = std::min<int>(256, samplesCount - samplesProcessed);
477 summary.RMS =
std::sqrt(summary.RMS / samplesToProcess);
478 samplesProcessed += samplesToProcess;
481 samplesProcessed = 0;
484 const auto samplesToProcess = std::min<int>(65536, samplesCount - samplesProcessed);
485 summary.RMS =
std::sqrt(summary.RMS / samplesToProcess);
486 samplesProcessed += samplesToProcess;
493 Exporter exporter { block };
494 return exporter.Compress();
497std::optional<DecompressedBlock>
500 if (data ==
nullptr ||
size == 0)
505 if (!importer.Unpack())
510 result.
BlockId = importer.BlockId;
511 result.Format = importer.Format;
513 const auto sampleSize =
SAMPLE_SIZE(importer.Format);
515 result.Data.resize(importer.SamplesCount * sampleSize);
520 result.Data.data(), importer.Int16Buffer.data(), result.Data.size());
526 result.Data.data(), importer.Int32Buffer.data(), result.Data.size());
532 result.Data.data(), importer.FloatBuffer.data(), result.Data.size());
FromCharsResult FromChars(const char *buffer, const char *last, float &value) noexcept
Parse a string into a single precision floating point value, always uses the dot as decimal.
Declare functions to convert numeric types to string representation.
Singleton class which actually imports the audio, using ImportPlugin objects that are registered by m...
Positions or offsets within audio files need a wide type.
void UpdateRMS(DecompressedBlock &block, const std::vector< T > &data)
float GetFloatValue(float value) noexcept
std::optional< DecompressedBlock > DecompressBlock(const void *data, const std::size_t size)
std::vector< uint8_t > CompressBlock(const LockedBlock &block)
const char * end(const char *str) noexcept
SizeType< float > Size
Alias for SizeType<float>
__finl float_x4 __vecc sqrt(const float_x4 &a)
std::vector< MinMaxRMS > Summary256
std::vector< MinMaxRMS > Summary64k
static int WriteBlock(void *id, void *data, int32_t length)
Exporter(LockedBlock block)
void Feed(int32_t *data, int32_t count)
std::vector< uint8_t > CompressedData
std::vector< uint8_t > Compress()
static int raw_set_pos_rel(void *id, int64_t delta, int mode)
static int32_t raw_write_bytes(void *id, void *data, int32_t bcount)
Importer(const void *data, const int64_t size)
static int raw_push_back_byte(void *id, int c)
static int64_t raw_get_pos(void *id)
static int32_t raw_read_bytes(void *id, void *data, int32_t bcount)
static int64_t raw_get_length(void *id)
static int raw_close_stream(void *)
static int raw_set_pos_abs(void *id, int64_t pos)
std::vector< int16_t > Int16Buffer
std::string ReadTag(const char *tagName)
std::vector< int32_t > Int32Buffer
static int raw_can_seek(void *)
std::vector< float > FloatBuffer