96 std::uint64_t{1} << 30u;
111 && (fft_size & (fft_size - 1)) == 0
113 && analysis_hop <= fft_size / 2;
119inline constexpr std::int64_t
121 bool full_overlap_stream_start)
noexcept {
122 if (!full_overlap_stream_start || fft_size <= 0 || analysis_hop <= 0)
124 return -
static_cast<std::int64_t
>((fft_size - 1) / analysis_hop) * analysis_hop;
131template <
typename SampleType>
133 std::int64_t first_frame_start,
134 std::int64_t position)
noexcept {
135 if (window ==
nullptr || fft_size <= 0 || hop <= 0 || position < first_frame_start)
137 const std::int64_t lowest =
138 std::max(first_frame_start, position -
static_cast<std::int64_t
>(fft_size) + 1);
139 const std::int64_t first_k = (lowest - first_frame_start + hop - 1) / hop;
141 for (std::int64_t start = first_frame_start + first_k * hop; start <= position; start += hop) {
142 const auto w =
static_cast<double>(window[
static_cast<std::size_t
>(position - start)]);
150template <
typename SampleType>
154 static_assert(std::is_floating_point_v<SampleType>);
156 || config.channels < 1 || config.max_block <= 0)
158 if (config.guarded_split && config.defer_synthesis)
161 const int max_synthesis_hop = config.max_synthesis_hop > 0
162 ? config.max_synthesis_hop
163 : 2 * config.analysis_hop;
164 if (max_synthesis_hop <= 0)
return std::nullopt;
166 const auto fft_size =
static_cast<std::uint64_t
>(config.fft_size);
167 const auto channels =
static_cast<std::uint64_t
>(config.channels);
168 const auto max_block =
static_cast<std::uint64_t
>(config.max_block);
169 const auto synthesis_hop =
static_cast<std::uint64_t
>(max_synthesis_hop);
170 const auto worst_frames = max_block /
static_cast<std::uint64_t
>(config.analysis_hop) + 2u;
172 std::uint64_t backlog = 0;
173 std::uint64_t ring_span = 0;
182 std::uint64_t ring_size = 1;
183 while (ring_size < ring_span) ring_size <<= 1u;
185 const auto num_bins = fft_size / 2u + 1u;
188 std::numeric_limits<std::uint64_t>::max(),
191 std::numeric_limits<std::uint64_t>::max(),
194 std::numeric_limits<std::uint64_t>::max(),
199 std::uint64_t fft_retained_bytes = 0;
202 || !charge.
add<SampleType>(ring_size)
203 || !charge.
add<SampleType>(fft_size)
204 || !charge.
add<SampleType>(fft_size)
206 || !charge.
add<std::complex<SampleType>*>(channels)
212 !charge.
add<SampleType>(fft_size)))
216 geometry.
num_bins =
static_cast<int>(num_bins);
217 geometry.
ring_size =
static_cast<int>(ring_size);
224template <
typename SampleType =
float>
237 assert(geometry.has_value());
238 if (!geometry)
return;
241 config_.max_synthesis_hop = geometry->max_synthesis_hop;
242 num_bins_ = geometry->num_bins;
244 config_.fft_size, config_.analysis_hop, config_.full_overlap_stream_start);
258 const int n = config_.fft_size, h = config_.analysis_hop;
260 for (
int j = -n / h - 1; j <= n / h + 1; ++j) {
261 const int idx =
center - j * h - (n / 2);
262 if (idx >= 0 && idx < n) {
263 const SampleType w = window_[
static_cast<size_t>(idx)];
264 steady +=
static_cast<double>(w) * w;
267 min_norm_ = std::max(
static_cast<SampleType
>(steady) * SampleType{0.25f},
270 ring_size_ = geometry->ring_size;
271 ring_mask_ = ring_size_ - 1;
273 input_ring_.assign(
static_cast<size_t>(geometry->input_ring_elements),
275 output_ring_.assign(
static_cast<size_t>(geometry->output_ring_elements),
277 norm_ring_.assign(ring_size_, SampleType{0.0f});
279 frames_.assign(
static_cast<size_t>(geometry->frame_elements),
280 std::complex<SampleType>(SampleType{0.0f}, SampleType{0.0f}));
281 frame_ptrs_.resize(config_.channels);
282 for (
int ch = 0; ch < config_.channels; ++ch)
283 frame_ptrs_[ch] = frames_.data() +
static_cast<size_t>(ch) * num_bins_;
285 time_buf_.assign(config_.fft_size, SampleType{0.0f});
286 guarded_numerator_.assign(
287 config_.guarded_split ?
static_cast<size_t>(geometry->input_ring_elements) : 0,
289 guarded_norm_.assign(config_.guarded_split ? config_.fft_size : 0, SampleType{0});
306 return first_frame_start_;
318 std::uint64_t fft_bytes = 0;
322 !charge.
add<SampleType>(input_ring_.capacity()) ||
323 !charge.
add<SampleType>(output_ring_.capacity()) ||
324 !charge.
add<SampleType>(norm_ring_.capacity()) ||
325 !charge.
add<SampleType>(time_buf_.capacity()) ||
326 !charge.
add<SampleType>(guarded_numerator_.capacity()) ||
327 !charge.
add<SampleType>(guarded_norm_.capacity()) ||
328 !charge.
add<std::complex<SampleType>>(frames_.capacity()) ||
329 !charge.
add<std::complex<SampleType>*>(frame_ptrs_.capacity()))
330 return std::numeric_limits<std::uint64_t>::max();
331 return charge.
total();
336 template <
typename Fn>
338 if (!config_.guarded_split || num_bins_ == 0)
340 if (count < 0 || count > config_.max_block || (count != 0 && !in))
342 for (
int ch = 0; count != 0 && ch < config_.channels; ++ch)
345 constexpr auto limit = std::numeric_limits<std::int64_t>::max();
346 if (samples_fed_ > limit - count || samples_fed_ + count > limit - config_.analysis_hop)
348 analyze(in, count, std::forward<Fn>(fn));
356 if (!config_.guarded_split || num_bins_ == 0)
358 if (guarded_stopped_)
360 const int n = config_.fft_size;
361 constexpr auto limit = std::numeric_limits<std::int64_t>::max();
362 if (synth_pos_ > limit - n)
364 if (synth_pos_ + n - read_pos_ > ring_size_)
368 for (
int ch = 0; ch < config_.channels; ++ch) {
371 for (
int bin = 0; bin < num_bins_; ++bin)
372 if (!std::isfinite(frames[ch][bin].real()) ||
373 !std::isfinite(frames[ch][bin].imag()))
375 if (frames[ch][0].imag() != SampleType{0} ||
376 frames[ch][num_bins_ - 1].imag() != SampleType{0})
379 const int skip = synth_pos_ < 0 ? static_cast<int>(-synth_pos_) : 0;
380 for (
int ch = 0; ch < config_.channels; ++ch) {
381 fft_.inverse_real_half(frames[ch], time_buf_.data());
382 for (
int i = 0;
i < n; ++
i)
383 if (!std::isfinite(time_buf_[
i]))
385 const auto* ring = output_ring_.data() +
static_cast<size_t>(ch) * ring_size_;
386 auto* staged = guarded_numerator_.data() +
static_cast<size_t>(ch) * n;
387 for (
int i = skip;
i < n; ++
i) {
388 const auto idx =
static_cast<size_t>((synth_pos_ +
i) & ring_mask_);
389 const SampleType contribution = time_buf_[
i] * window_[
i];
390 staged[
i] = ring[idx] + contribution;
391 if (!std::isfinite(contribution) || !std::isfinite(staged[
i]))
395 for (
int i = skip;
i < n; ++
i) {
396 const auto idx =
static_cast<size_t>((synth_pos_ +
i) & ring_mask_);
397 guarded_norm_[
i] = norm_ring_[idx] + window_[
i] * window_[
i];
398 if (!std::isfinite(guarded_norm_[
i]))
401 for (
int ch = 0; ch < config_.channels; ++ch) {
402 auto* ring = output_ring_.data() +
static_cast<size_t>(ch) * ring_size_;
403 const auto* staged = guarded_numerator_.data() +
static_cast<size_t>(ch) * n;
404 for (
int i = skip;
i < n; ++
i)
405 ring[
static_cast<size_t>((synth_pos_ +
i) & ring_mask_)] = staged[
i];
407 for (
int i = skip;
i < n; ++
i)
408 norm_ring_[
static_cast<size_t>((synth_pos_ +
i) & ring_mask_)] = guarded_norm_[
i];
409 available_ = std::max(available_, synth_pos_);
410 synth_pos_ += config_.analysis_hop;
418 if (!config_.guarded_split)
420 available_ = std::max(available_, synth_pos_);
421 guarded_stopped_ =
true;
427 int& consumed)
noexcept {
429 if (!config_.guarded_split || num_bins_ == 0)
431 if (count < 0 || count > config_.max_block || (count != 0 && !out))
433 for (
int ch = 0; count != 0 && ch < config_.channels; ++ch)
436 for (; consumed < count; ++consumed) {
437 if (read_pos_ >= available_)
439 const auto idx =
static_cast<size_t>(read_pos_ & ring_mask_);
440 const bool startup = !config_.full_overlap_stream_start && read_pos_ < config_.fft_size;
441 const SampleType norm =
442 startup ? std::max(norm_ring_[idx], min_norm_) : norm_ring_[idx];
443 if (!std::isfinite(norm))
445 for (
int ch = 0; ch < config_.channels; ++ch) {
446 const auto* ring = output_ring_.data() +
static_cast<size_t>(ch) * ring_size_;
447 auto& value = guarded_numerator_[
static_cast<size_t>(ch) * config_.fft_size];
448 value = norm > SampleType{1e-9f} ? ring[idx] / norm : SampleType{0};
449 if (!std::isfinite(value))
452 for (
int ch = 0; ch < config_.channels; ++ch) {
453 out[ch][consumed] = guarded_numerator_[
static_cast<size_t>(ch) * config_.fft_size];
454 output_ring_[
static_cast<size_t>(ch) * ring_size_ + idx] = SampleType{0};
456 norm_ring_[idx] = SampleType{0};
467 template <
typename Fn>
469 SampleType*
const* out,
472 assert(num_samples <= config_.max_block);
481 run_due_synthesis_(samples_fed_ + num_samples);
482 analyze(in, num_samples, [&](std::complex<SampleType>*
const* frames,
484 on_frames(frames, bins);
485 if (config_.defer_synthesis)
486 begin_deferred_synthesis_(frames);
490 run_due_synthesis_(samples_fed_);
495 for (
int i = 0;
i < num_samples; ++
i) {
496 if (out_count_ < lat) {
497 for (
int ch = 0; ch < config_.channels; ++ch)
498 out[ch][
i] = SampleType{0.0f};
513 return static_cast<int>(next_frame_at_ - samples_fed_);
523 template <
typename Fn>
524 void analyze(
const SampleType*
const* in,
int num_samples, Fn&& on_frames) {
525 const int n = config_.fft_size;
527 while (done < num_samples) {
528 const auto until_frame =
static_cast<int>(
529 std::min<std::int64_t>(next_frame_at_ - samples_fed_,
530 static_cast<std::int64_t
>(num_samples - done)));
531 const int run = std::max(until_frame, 1);
532 for (
int ch = 0; ch < config_.channels; ++ch) {
533 SampleType* ring = input_ring_.data() +
static_cast<size_t>(ch) * n;
534 for (
int i = 0;
i < run; ++
i)
535 ring[(input_pos_ +
i) % n] = in[ch][done +
i];
537 input_pos_ = (input_pos_ + run) % n;
541 if (samples_fed_ == next_frame_at_) {
542 flush_deferred_synthesis_();
543 next_frame_at_ += config_.analysis_hop;
544 emit_frame(on_frames);
556 assert(synthesis_hop > 0 && synthesis_hop <= config_.max_synthesis_hop);
557 for (
int ch = 0; ch < config_.channels; ++ch)
558 synthesize_channel_(frames, ch);
559 finish_synthesis_(synthesis_hop);
565 return static_cast<int>(available_ - read_pos_);
573 for (
int i = 0;
i < num_samples; ++
i) {
574 if (read_pos_ < available_) {
577 for (
int ch = 0; ch < config_.channels; ++ch)
578 out[ch][
i] = SampleType{0.0f};
584 std::fill(input_ring_.begin(), input_ring_.end(), SampleType{0.0f});
585 std::fill(output_ring_.begin(), output_ring_.end(), SampleType{0.0f});
586 std::fill(norm_ring_.begin(), norm_ring_.end(), SampleType{0.0f});
587 std::fill(frames_.begin(), frames_.end(),
588 std::complex<SampleType>(SampleType{0.0f}, SampleType{0.0f}));
591 next_frame_at_ = config_.fft_size + first_frame_start_;
592 synth_pos_ = first_frame_start_;
596 deferred_frames_ =
nullptr;
597 deferred_next_channel_ = 0;
598 guarded_stopped_ =
false;
606 void synthesize_channel_(std::complex<SampleType>*
const* frames,
int ch) {
609 synth_pos_ < 0 ? static_cast<int>(std::min<std::int64_t>(-synth_pos_, n)) : 0;
614 SampleType* ring = output_ring_.data() +
static_cast<size_t>(ch) * ring_size_;
615 for (
int i = skip;
i < n; ++
i) {
616 const auto idx =
static_cast<size_t>((synth_pos_ +
i) & ring_mask_);
617 ring[idx] += time_buf_[
static_cast<size_t>(
i)] * window_[
static_cast<size_t>(
i)];
623 void finish_synthesis_(
int synthesis_hop) {
626 synth_pos_ < 0 ? static_cast<int>(std::min<std::int64_t>(-synth_pos_, n)) : 0;
627 for (
int i = skip;
i < n; ++
i) {
628 const auto idx =
static_cast<size_t>((synth_pos_ +
i) & ring_mask_);
629 norm_ring_[idx] += window_[
static_cast<size_t>(
i)] * window_[
static_cast<size_t>(
i)];
631 synth_pos_ += synthesis_hop;
633 available_ = std::max(available_, synth_pos_ - synthesis_hop);
636 void begin_deferred_synthesis_(std::complex<SampleType>*
const* frames) {
637 deferred_frames_ = frames;
638 deferred_next_channel_ = 0;
639 deferred_frame_at_ = samples_fed_;
643 void run_due_synthesis_(std::int64_t fed) {
644 const int channels = config_.channels;
645 while (deferred_frames_ !=
nullptr) {
646 const std::int64_t due =
647 deferred_frame_at_ +
static_cast<std::int64_t
>(config_.analysis_hop) *
648 (deferred_next_channel_ + 1) / (
channels + 1);
651 step_deferred_synthesis_();
655 void step_deferred_synthesis_() {
656 synthesize_channel_(deferred_frames_, deferred_next_channel_);
657 if (++deferred_next_channel_ == config_.channels) {
658 finish_synthesis_(config_.analysis_hop);
659 deferred_frames_ =
nullptr;
663 void flush_deferred_synthesis_() {
664 while (deferred_frames_ !=
nullptr)
665 step_deferred_synthesis_();
670 void pop_one(SampleType*
const* out,
int i) {
673 assert(read_pos_ < available_ + config_.analysis_hop);
674 const auto idx =
static_cast<size_t>(read_pos_ & ring_mask_);
680 const bool startup_edge =
681 !config_.full_overlap_stream_start && read_pos_ < config_.fft_size;
682 const SampleType norm = startup_edge
683 ? std::max(norm_ring_[idx], min_norm_)
685 for (
int ch = 0; ch < config_.channels; ++ch) {
687 output_ring_.data() +
static_cast<size_t>(ch) * ring_size_;
689 norm > SampleType{1e-9f} ?
ring[idx] / norm : SampleType{0.0f};
690 ring[idx] = SampleType{0.0f};
692 norm_ring_[idx] = SampleType{0.0f};
698 template <
typename Fn>
699 void emit_frame(Fn&& on_frames) {
700 const int n = config_.fft_size;
701 for (
int ch = 0; ch < config_.channels; ++ch) {
702 const SampleType*
ring =
703 input_ring_.data() +
static_cast<size_t>(ch) * n;
704 for (
int i = 0;
i <
n; ++
i)
705 time_buf_[
static_cast<size_t>(
i)] =
706 ring[(input_pos_ +
i) % n] * window_[
static_cast<size_t>(
i)];
707 fft_.forward_real_half(time_buf_.data(),
708 frames_.data() +
static_cast<size_t>(ch) * num_bins_);
710 on_frames(frame_ptrs_.data(), num_bins_);
713 SpectralFrameEngineConfig config_;
714 FftT<SampleType> fft_{2048};
715 std::vector<SampleType> window_;
719 SampleType min_norm_ = SampleType{1e-9f};
720 std::int64_t first_frame_start_ = 0;
722 std::vector<SampleType> input_ring_;
723 std::vector<SampleType> output_ring_;
724 std::vector<SampleType> norm_ring_;
726 std::vector<std::complex<SampleType>> frames_;
727 std::vector<std::complex<SampleType>*> frame_ptrs_;
728 std::vector<SampleType> time_buf_;
729 std::vector<SampleType> guarded_numerator_;
730 std::vector<SampleType> guarded_norm_;
731 bool guarded_stopped_ =
false;
734 std::int64_t samples_fed_ = 0;
735 std::int64_t next_frame_at_ = 0;
736 std::int64_t synth_pos_ = 0;
737 std::int64_t available_ = 0;
738 std::int64_t read_pos_ = 0;
739 std::int64_t out_count_ = 0;
743 std::complex<SampleType>*
const* deferred_frames_ =
nullptr;
744 int deferred_next_channel_ = 0;
745 std::int64_t deferred_frame_at_ = 0;
Definition checked_allocation.hpp:57
bool add(std::uint64_t elements) noexcept
Definition checked_allocation.hpp:63
std::uint64_t total() const noexcept
Definition checked_allocation.hpp:83
bool add_retained_bytes(std::uint64_t bytes) noexcept
Definition checked_allocation.hpp:78
void inverse_real_half(const std::complex< SampleType > *input, SampleType *output, SampleType scale) const
Inverse of forward_real_half().
Definition fft.hpp:469
Streaming multichannel STFT/WOLA engine.
Definition spectral_frame_engine.hpp:225
int latency_samples() const
Fixed delay of the equal-hop process() path.
Definition spectral_frame_engine.hpp:299
void process(const SampleType *const *in, SampleType *const *out, int num_samples, Fn &&on_frames)
Equal-hop streaming: push num_samples per channel, invoke on_frames(std::complex<SampleType>* const* ...
Definition spectral_frame_engine.hpp:468
std::int64_t first_frame_start() const
Stream position of the first analysis frame after prepare()/reset(): 0 without full-overlap stream st...
Definition spectral_frame_engine.hpp:305
SpectralSplitResult synthesize_frame_guarded(const std::complex< SampleType > *const *frames) noexcept
Equal-hop split synthesis.
Definition spectral_frame_engine.hpp:355
int num_bins() const
Definition spectral_frame_engine.hpp:311
void stop_synthesis_guarded() noexcept
After a fatal frame at the current origin, prior samples are final: this frame cannot contribute befo...
Definition spectral_frame_engine.hpp:417
void prepare(const SpectralFrameEngineConfig &config)
RT contract: prepare() allocates FFT/window/ring/frame storage and is not audio-thread safe.
Definition spectral_frame_engine.hpp:235
int fft_size() const
Definition spectral_frame_engine.hpp:309
void analyze(const SampleType *const *in, int num_samples, Fn &&on_frames)
Split API — analysis only.
Definition spectral_frame_engine.hpp:524
SpectralSplitResult read_output_guarded(SampleType *const *out, int count, int &consumed) noexcept
Pop a finite prefix and return its length.
Definition spectral_frame_engine.hpp:426
int available_output() const
Split API — number of final (fully overlapped) output samples that can be read right now.
Definition spectral_frame_engine.hpp:564
SpectralFrameEngineT()=default
void reset()
Definition spectral_frame_engine.hpp:583
std::uint64_t retained_storage_bytes() const noexcept
Logical retained allocations, using actual container capacities and the selected FFT provider's backi...
Definition spectral_frame_engine.hpp:316
void synthesize_frame(std::complex< SampleType > *const *frames, int synthesis_hop)
Split API — overlap-add one spectral frame (all channels) at the current synthesis position,...
Definition spectral_frame_engine.hpp:555
int channels() const
Definition spectral_frame_engine.hpp:312
int analysis_hop() const
Definition spectral_frame_engine.hpp:310
SpectralSplitResult analyze_guarded(const SampleType *const *in, int count, Fn &&fn)
Checked split analysis refuses the whole block before ingest on a clock or block-limit error.
Definition spectral_frame_engine.hpp:337
int samples_until_next_frame() const
Samples that must still be fed before the next analysis frame completes (>= 1).
Definition spectral_frame_engine.hpp:512
void read_output(SampleType *const *out, int num_samples)
Split API — pop exactly num_samples per channel into out.
Definition spectral_frame_engine.hpp:572
static std::vector< SampleType > generate(int size, Type type, SampleType param=SampleType{0.0f})
Definition windowing.hpp:56
Type
Definition windowing.hpp:43
@ hann
Definition windowing.hpp:45
@ ring
Definition string.hpp:18
Definition additive_bank.hpp:218
@ NotPrepared
Definition source_filter_analysis.hpp:30
@ Ok
Definition source_filter_analysis.hpp:29
bool checked_fft_retained_bytes(std::uint64_t fft_size, std::uint64_t target_max_bytes, std::uint64_t &bytes) noexcept
Complete retained-storage contract for one prepared FftT.
Definition fft.hpp:133
std::optional< SpectralFrameEngineGeometry > checked_spectral_frame_engine_geometry(const SpectralFrameEngineConfig &config, std::uint64_t target_max_bytes=kTargetAddressMaximumBytes) noexcept
Derive every integer and typed backing-store capacity used by prepare().
Definition spectral_frame_engine.hpp:151
@ center
Definition multi_channel_meter.hpp:68
bool is_valid_spectral_frame_geometry(int fft_size, int analysis_hop) noexcept
Definition spectral_frame_engine.hpp:108
SpectralFrameEngineT< double > SpectralFrameEngine64
Definition spectral_frame_engine.hpp:749
SpectralFrameEngineT< float > SpectralFrameEngine
Definition spectral_frame_engine.hpp:748
SpectralSplitResult
Definition spectral_frame_engine.hpp:81
@ StreamStopped
Definition spectral_frame_engine.hpp:90
@ OutputUnderrun
Definition spectral_frame_engine.hpp:89
@ InvalidFrame
Definition spectral_frame_engine.hpp:85
@ NotPrepared
Definition spectral_frame_engine.hpp:83
@ Ok
Definition spectral_frame_engine.hpp:82
@ ChronologyExhausted
Definition spectral_frame_engine.hpp:86
@ NonfiniteSynthesis
Definition spectral_frame_engine.hpp:88
@ InvalidBlock
Definition spectral_frame_engine.hpp:84
@ CapacityExceeded
Definition spectral_frame_engine.hpp:87
constexpr int kSpectralFrameEngineMaximumFftSize
Definition spectral_frame_engine.hpp:94
bool checked_capacity_product(std::uint64_t lhs, std::uint64_t rhs, std::uint64_t maximum, std::uint64_t &product) noexcept
Definition checked_allocation.hpp:12
bool checked_capacity_sum(std::uint64_t lhs, std::uint64_t rhs, std::uint64_t maximum, std::uint64_t &sum) noexcept
Definition checked_allocation.hpp:21
constexpr std::uint64_t kTargetAddressMaximumBytes
Definition checked_allocation.hpp:9
@ i
Definition formant_filter_bank.hpp:20
constexpr int kSpectralFrameEngineMinimumFftSize
Definition spectral_frame_engine.hpp:93
constexpr std::int64_t spectral_frame_engine_first_frame_start(int fft_size, int analysis_hop, bool full_overlap_stream_start) noexcept
Stream position of the first analysis frame after prepare()/reset().
Definition spectral_frame_engine.hpp:120
double spectral_ola_window_energy(const SampleType *window, int fft_size, int hop, std::int64_t first_frame_start, std::int64_t position) noexcept
Accumulated squared synthesis window at stream position for equal-hop frames of length fft_size start...
Definition spectral_frame_engine.hpp:132
constexpr std::uint64_t kSpectralFrameEngineMaximumRingSize
Definition spectral_frame_engine.hpp:95
@ n
Definition input_events.hpp:40
Configuration for a SpectralFrameEngine.
Definition spectral_frame_engine.hpp:56
bool guarded_split
Prepare transactional inverse/OLA scratch for the guarded split API.
Definition spectral_frame_engine.hpp:78
int channels
Definition spectral_frame_engine.hpp:59
int max_block
Definition spectral_frame_engine.hpp:60
WindowFunction::Type window
Definition spectral_frame_engine.hpp:62
int fft_size
Definition spectral_frame_engine.hpp:57
int analysis_hop
Definition spectral_frame_engine.hpp:58
int max_synthesis_hop
Definition spectral_frame_engine.hpp:61
bool full_overlap_stream_start
true: analysis frames start before the stream so the first sample after prepare()/reset() gets full o...
Definition spectral_frame_engine.hpp:70
bool defer_synthesis
process() only: run each channel's inverse transform and overlap-add at its own point in the hop afte...
Definition spectral_frame_engine.hpp:75
Definition spectral_frame_engine.hpp:98
std::uint64_t frame_elements
Definition spectral_frame_engine.hpp:104
int ring_size
Definition spectral_frame_engine.hpp:101
std::uint64_t output_ring_elements
Definition spectral_frame_engine.hpp:103
std::uint64_t retained_bytes
Definition spectral_frame_engine.hpp:105
int num_bins
Definition spectral_frame_engine.hpp:100
int max_synthesis_hop
Definition spectral_frame_engine.hpp:99
std::uint64_t input_ring_elements
Definition spectral_frame_engine.hpp:102