HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
audio_sample_unpacker.hpp
1// Copyright Take Vos 2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7//#include "audio_sample_format.hpp"
8#include "../utility/utility.hpp"
9#include "../macros.hpp"
10#include <hikocpu/hikocpu.hpp>
11#include <cstddef>
12#include <bit>
13
14hi_export_module(hikogui.audio.audio_sample_unpacker);
15
16hi_export namespace hi { inline namespace v1 {
17
18hi_export class audio_sample_unpacker {
19public:
28 audio_sample_unpacker(audio_sample_format format, std::size_t stride) noexcept : _format(format), _stride(stride)
29 {
30 _load_shuffle_indices = format.load_shuffle_indices(stride);
31 _concat_shuffle_indices = format.concat_shuffle_indices(stride);
32
33 _multiplier = f32x4::broadcast(format.unpack_multiplier());
34 _num_chunks_per_quad = format.num_chunks_per_quad(stride);
35 _chunk_stride = format.chunk_stride(stride);
36
37 _direction = format.endian == std::endian::little ? -1 : 1;
38 _start_byte = format.endian == std::endian::little ? format.num_bytes - 1 : 0;
39 _align_shift = 32 - format.num_bytes * 8;
40 }
41
48 void operator()(std::byte const *hi_restrict src, float *hi_restrict dst, std::size_t num_samples) const noexcept
49 {
50 hi_assert(src != nullptr);
51 hi_assert(dst != nullptr);
52
53 // Calculate a conservative number of samples that can be copied quickly
54 // without overflowing the src buffer.
55 auto const *const dst_end = dst + num_samples;
56 auto const *const dst_fast_end = dst + _format.num_fast_quads(_stride, num_samples) * 4;
57
58 if (_format.is_float) {
59 while (dst != dst_fast_end) {
60 auto const int_samples =
61 load_samples(src, _load_shuffle_indices, _concat_shuffle_indices, _num_chunks_per_quad, _chunk_stride);
62 auto const float_samples = f32x4::cast_from(int_samples);
63 store_samples(dst, float_samples);
64 }
65 while (dst != dst_end) {
66 auto const int_sample = load_sample(src, _stride, _format.num_bytes, _direction, _start_byte, _align_shift);
67 auto const float_sample = std::bit_cast<float>(int_sample);
68 store_sample(dst, float_sample);
69 }
70
71 } else {
72 auto const multiplier = _multiplier;
73 while (dst != dst_fast_end) {
74 auto const int_samples =
75 load_samples(src, _load_shuffle_indices, _concat_shuffle_indices, _num_chunks_per_quad, _chunk_stride);
76 auto const float_samples = static_cast<f32x4>(int_samples) * multiplier;
77 store_samples(dst, float_samples);
78 }
79 while (dst != dst_end) {
80 auto const int_sample = load_sample(src, _stride, _format.num_bytes, _direction, _start_byte, _align_shift);
81 auto const float_sample = static_cast<float>(int_sample) * get<0>(multiplier);
82 store_sample(dst, float_sample);
83 }
84 }
85 }
86
87private:
88 f32x4 _multiplier;
89 i8x16 _load_shuffle_indices;
90 i8x16 _concat_shuffle_indices;
91 std::size_t _num_chunks_per_quad;
92 std::size_t _stride;
93 std::size_t _chunk_stride;
94 audio_sample_format _format;
95 int _direction;
96 int _start_byte;
97 int _align_shift;
98
99 //[[nodiscard]] std::size_t calculate_num_fast_samples(std::size_t num_samples) const noexcept;
100
101 [[nodiscard]] static int32_t load_sample(
102 std::byte const *hi_restrict & src,
103 std::size_t stride,
104 int num_bytes,
105 int direction,
106 int start_byte,
107 int align_shift) noexcept
108 {
109 hi_axiom(src != nullptr);
110 hi_axiom(num_bytes >= 1 && num_bytes <= 4);
111 hi_axiom(direction == 1 || direction == -1);
112 hi_axiom(start_byte <= 3);
113 hi_axiom(align_shift <= 32);
114 hi_axiom(stride >= num_bytes);
115
116 auto p = src + start_byte;
117 hi_axiom(p != nullptr);
118
119 uint32_t r = 0;
120 do {
121 r <<= 8;
122 r |= static_cast<uint32_t>(static_cast<uint8_t>(*p));
123 p += direction;
124 } while (--num_bytes);
125
126 // Align the bits to the left to allow for sign extension.
127 r <<= align_shift;
128
129 src += stride;
130 return truncate<int32_t>(r);
131 }
132
133 [[nodiscard]] static i8x16 load_samples(std::byte const *hi_restrict & src, i8x16 load_shuffle_indices, std::size_t stride) noexcept
134 {
135 hi_axiom(src != nullptr);
136 hi_axiom(stride > 0);
137
138 auto r = permute(i8x16::load(src), load_shuffle_indices);
139 src += stride;
140 return r;
141 }
142
143 [[nodiscard]] static i32x4 load_samples(
144 std::byte const *hi_restrict & src,
145 i8x16 load_shuffle_indices,
146 i8x16 concat_shuffle_indices,
147 std::size_t num_chunks,
148 std::size_t stride) noexcept
149 {
150 hi_assert(src != nullptr);
151 hi_assert(num_chunks > 0 and num_chunks <= 4);
152 hi_assert(stride > 0);
153
154 auto int_samples = i8x16{};
155 do {
156 int_samples = permute(int_samples, concat_shuffle_indices);
157 // Due to int_samples reset the dependency is broken on the first iteration, the load_samples
158 // call here should be pipelined in parallel with the first shuffle.
159 int_samples |= load_samples(src, load_shuffle_indices, stride);
160 } while (--num_chunks);
161
162 return std::bit_cast<i32x4>(int_samples);
163 }
164
165 static void store_sample(float *hi_restrict & dst, float sample) noexcept
166 {
167 hi_axiom(dst != nullptr);
168 *(dst++) = sample;
169 }
170
171 static void store_samples(float *hi_restrict & dst, f32x4 samples) noexcept
172 {
173 hi_axiom(dst != nullptr);
174 samples.store(reinterpret_cast<std::byte *>(dst));
175 dst += 4;
176 }
177};
178
179}} // namespace hi::inline v1
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
Audio sample format.
Definition audio_sample_format.hpp:30
uint8_t num_bytes
The number of bytes of the container.
Definition audio_sample_format.hpp:34
bool is_float
The numeric type is floating point.
Definition audio_sample_format.hpp:56
std::size_t num_fast_quads(std::size_t stride, std::size_t num_samples) const noexcept
Calculate the number of 4 sample-quads can be handled as chunked loads and stores.
Definition audio_sample_format.hpp:238
Definition audio_sample_unpacker.hpp:18
void operator()(std::byte const *hi_restrict src, float *hi_restrict dst, std::size_t num_samples) const noexcept
Unpack samples.
Definition audio_sample_unpacker.hpp:48
audio_sample_unpacker(audio_sample_format format, std::size_t stride) noexcept
Audio sample unpacker One instance of this class can be used to unpack multiple buffers either from o...
Definition audio_sample_unpacker.hpp:28