34 static_assert(std::is_floating_point_v<SampleType>);
54 crossfade > std::numeric_limits<int>::max() - 2) {
59 if constexpr (std::numeric_limits<SampleType>::digits < std::numeric_limits<int>::digits) {
60 constexpr auto exact_integer_limit = std::uint64_t{1}
61 << std::numeric_limits<SampleType>::digits;
62 if (
static_cast<std::uint64_t
>(bounded_capacity) > exact_integer_limit ||
63 static_cast<std::uint64_t
>(
channels) > exact_integer_limit) {
68 const auto channel_count =
static_cast<std::size_t
>(
channels);
69 const auto frame_capacity =
static_cast<std::size_t
>(bounded_capacity);
70 if (channel_count > std::numeric_limits<std::size_t>::max() / frame_capacity) {
74 const auto elements = channel_count * frame_capacity;
75 if (elements > ring_.max_size() || elements > loop_.max_size()) {
80 std::vector<SampleType> replacement_ring(elements, SampleType{});
81 std::vector<SampleType> replacement_loop(elements, SampleType{});
82 ring_.swap(replacement_ring);
83 loop_.swap(replacement_loop);
85 capacity_ = bounded_capacity;
102 return static_cast<int>(std::min<long long>(written_, capacity_));
111 return (ring_.capacity() + loop_.capacity()) *
sizeof(SampleType);
115 void write(
const SampleType*
const* in,
int n) {
116 if (n <= 0 || channels_ <= 0 || capacity_ <= 0 || in ==
nullptr)
118 for (
int ch = 0; ch < channels_; ++ch) {
119 if (in[ch] ==
nullptr)
122 for (
int ch = 0; ch < channels_; ++ch) {
123 SampleType* r = ring_.data() +
static_cast<size_t>(ch) * capacity_;
124 const SampleType* src = in[ch];
126 for (
int i = 0;
i < n; ++
i) {
127 r[wp] = std::isfinite(
static_cast<double>(src[
i])) ? src[
i] : SampleType{};
128 if (++wp >= capacity_)
132 write_pos_ =
static_cast<int>((
static_cast<std::int64_t
>(write_pos_) + n) % capacity_);
133 written_ = std::min<long long>(capacity_, written_ + std::min(n, capacity_));
143 if (loop_samples <= 0)
145 if (loop_samples > capacity_)
150 const int start =
static_cast<int>(
151 (
static_cast<std::int64_t
>(write_pos_) - loop_samples + capacity_) % capacity_);
153 loop_len_ = loop_samples;
162 if (!frozen_ || channel < 0 || channel >= channels_ || frame < 0 || frame >= loop_len_)
164 auto loop_index =
static_cast<std::size_t
>(loop_start_) +
static_cast<std::size_t
>(frame);
165 if (loop_index >=
static_cast<std::size_t
>(capacity_))
166 loop_index -=
static_cast<std::size_t
>(capacity_);
167 return loop_[
static_cast<std::size_t
>(channel) * capacity_ + loop_index];
173 const int avail =
static_cast<int>(std::min<long long>(written_, capacity_));
181 const int xf = std::min(crossfade_, std::max(0, avail - 1));
182 int len = std::clamp(loop_samples, 1, std::max(1, avail - xf));
186 const int span = len + xf;
187 const auto capacity =
static_cast<std::size_t
>(capacity_);
189 (
static_cast<std::size_t
>(write_pos_) +
capacity -
static_cast<std::size_t
>(span)) %
191 for (
int ch = 0; ch < channels_; ++ch) {
192 const SampleType* r = ring_.data() +
static_cast<size_t>(ch) * capacity_;
193 SampleType* lp = loop_.data() +
static_cast<size_t>(ch) * capacity_;
194 for (
int i = 0;
i < len; ++
i)
195 lp[
i] = r[(start +
static_cast<std::size_t
>(
i)) %
capacity];
198 for (
int i = 0;
i < xf; ++
i) {
200 (xf > 1) ?
static_cast<SampleType
>(
i) /
static_cast<SampleType
>(xf - 1)
202 const SampleType g_head = std::sin(
static_cast<SampleType
>(0.5) *
203 static_cast<SampleType
>(3.14159265358979) * t);
204 const SampleType g_tail = std::cos(
static_cast<SampleType
>(0.5) *
205 static_cast<SampleType
>(3.14159265358979) * t);
206 const SampleType head = lp[
i];
207 const SampleType tail =
208 r[(start +
static_cast<std::size_t
>(len) +
static_cast<std::size_t
>(
i)) %
210 lp[
i] = head * g_head + tail * g_tail;
224 void read(SampleType*
const* out,
int n) {
225 if (!frozen_ || loop_len_ <= 0 || n <= 0 || out ==
nullptr)
227 for (
int ch = 0; ch < channels_; ++ch) {
228 if (out[ch] ==
nullptr)
231 for (
int ch = 0; ch < channels_; ++ch) {
232 SampleType* dst = out[ch];
234 for (
int i = 0;
i < n; ++
i) {
236 if (++p >= loop_len_)
240 play_pos_ =
static_cast<int>(
241 (
static_cast<std::uint64_t
>(play_pos_) +
static_cast<std::uint64_t
>(n)) %
242 static_cast<std::uint64_t
>(loop_len_));
265 std::vector<SampleType> out;
266 if (!frozen_ || loop_len_ <= 0)
269 static_cast<std::size_t
>(loop_len_) *
static_cast<std::size_t
>(channels_);
270 if (payload > out.max_size() - 4)
272 out.reserve(4 + payload);
273 out.push_back(
static_cast<SampleType
>(channels_));
274 out.push_back(
static_cast<SampleType
>(loop_len_));
275 out.push_back(
static_cast<SampleType
>(crossfade_));
276 out.push_back(
static_cast<SampleType
>(play_pos_));
277 for (
int ch = 0; ch < channels_; ++ch) {
278 for (
int i = 0;
i < loop_len_; ++
i)
286 bool restore(
const std::vector<SampleType>& blob) {
289 for (
const auto value : blob) {
290 if (!std::isfinite(
static_cast<double>(value)))
293 const auto valid_integer = [](SampleType value, SampleType minimum,
295 return value >= minimum && value <=
maximum && std::trunc(value) == value;
297 if (!valid_integer(blob[0], SampleType{1},
static_cast<SampleType
>(channels_)) ||
298 !valid_integer(blob[1], SampleType{1},
static_cast<SampleType
>(capacity_)) ||
299 !valid_integer(blob[2], SampleType{},
static_cast<SampleType
>(capacity_)))
301 const int ch =
static_cast<int>(blob[0]);
302 const int len =
static_cast<int>(blob[1]);
303 if (ch != channels_ ||
304 !valid_integer(blob[3], SampleType{},
static_cast<SampleType
>(len - 1)))
306 const auto expected_size =
static_cast<std::size_t
>(4) +
307 static_cast<std::size_t
>(len) *
static_cast<std::size_t
>(ch);
308 if (blob.size() != expected_size)
310 const int pp =
static_cast<int>(blob[3]);
315 for (
int c = 0;
c < channels_; ++
c) {
316 SampleType* lp = loop_.data() +
static_cast<size_t>(
c) * capacity_;
317 for (
int i = 0;
i < len; ++
i)
325 void fail_prepare() noexcept {
342 std::vector<SampleType> ring_;
343 std::vector<SampleType> loop_;
345 long long written_ = 0;
346 bool frozen_ =
false;
Definition freeze_loop_sampler.hpp:33
void release()
Definition freeze_loop_sampler.hpp:218
CaptureResult try_freeze_recent(int loop_samples) noexcept
Capture exactly the most recent loop_samples frames.
Definition freeze_loop_sampler.hpp:142
CaptureResult
Definition freeze_loop_sampler.hpp:37
@ Success
Definition freeze_loop_sampler.hpp:38
@ InvalidLength
Definition freeze_loop_sampler.hpp:39
@ ExceedsCapacity
Definition freeze_loop_sampler.hpp:41
@ InsufficientHistory
Definition freeze_loop_sampler.hpp:40
std::vector< SampleType > snapshot() const
Serialize the frozen loop: [channels][loop_len][crossfade][play_pos] then loop_len * channels samples...
Definition freeze_loop_sampler.hpp:264
void prepare(int channels, int capacity, int crossfade)
Definition freeze_loop_sampler.hpp:52
bool frozen() const noexcept
Definition freeze_loop_sampler.hpp:104
bool restore(const std::vector< SampleType > &blob)
Restore a loop produced by snapshot().
Definition freeze_loop_sampler.hpp:286
void clear_history() noexcept
Invalidate rolling input continuity without changing a captured loop.
Definition freeze_loop_sampler.hpp:256
void read(SampleType *const *out, int n)
Play the loop into out (frozen only).
Definition freeze_loop_sampler.hpp:224
void reset()
Definition freeze_loop_sampler.hpp:245
int capacity() const noexcept
Definition freeze_loop_sampler.hpp:98
std::size_t retained_bytes() const noexcept
Definition freeze_loop_sampler.hpp:110
void freeze(int loop_samples)
Freeze the most recent loop_samples of recorded audio into a seamless loop.
Definition freeze_loop_sampler.hpp:172
int loop_length() const noexcept
Definition freeze_loop_sampler.hpp:107
void write(const SampleType *const *in, int n)
Record n frames into the ring (call every block, always).
Definition freeze_loop_sampler.hpp:115
SampleType loop_sample(int channel, int frame) const noexcept
Definition freeze_loop_sampler.hpp:161
int channels() const noexcept
Definition freeze_loop_sampler.hpp:95
int available_history() const noexcept
Definition freeze_loop_sampler.hpp:101
Definition additive_bank.hpp:218
@ c
Definition spectrum_trace.hpp:35
FreezeLoopSamplerT< float > FreezeLoopSampler
Definition freeze_loop_sampler.hpp:352
@ maximum
Definition spectrum_trace.hpp:34
@ i
Definition formant_filter_bank.hpp:20
FreezeLoopSamplerT< double > FreezeLoopSampler64
Definition freeze_loop_sampler.hpp:353
@ crossfade
Fade in over the configured crossfade, like a normal engage.
Definition freeze_hold.hpp:153