// Copyright 2022-2026 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#ifndef AEC_MEMORY_POOL_H
#define AEC_MEMORY_POOL_H

#include "xmath/xmath.h"
#include "aec_defines.h"

/**
 * @defgroup aec_memory_pool AEC memory pool
 */

/**
 * @brief aec_memory_pool_t
 *
 * Memory pool for AEC main filter and shared state buffers.
 *
 * This pool provides contiguous storage for all BFP (block floating-point from ``lib_xcore_math``) structures used by the main filter (`aec_filter_state_t`)
 * and the shared filter state (`aec_shared_filter_state_t`).
 * The `aec_init()` function initializes the BFP structures in the AEC state structures to point to
 * memory buffers from this pool during AEC initialisation.
 *
 * The memory pool allocates storage based on AEC compile-time configuration parameters:
 * - @ref AEC_MAX_Y_CHANNELS
 * - @ref AEC_MAX_X_CHANNELS
 * - @ref AEC_MAIN_FILTER_PHASES
 * - @ref AEC_SHADOW_FILTER_PHASES
 *
 * The same pool can be used to initialize AEC for any runtime configuration (passed as arguments to `aec_init()`)
 * that is a subset of the compile-time configuration (See @ref aec_phase_pool_capacity).
 *
 * @note
 * This structure exists to own memory, not to describe layout.
 * The memory pool acts as a linear allocation arena used by `aec_init()` to
 * initialise BFP structures in the AEC filter state structures. Memory is assigned
 * sequentially from the pool based on the runtime configuration (number of
 * channels and filter phases), and does not have a fixed or semantic mapping to
 * the individual fields of this struct.
 * The named members of this struct exist only to reserve sufficient contiguous
 * storage at compile time. They must not be interpreted as backing specific
 * components of `aec_filter_state_t`/`aec_shared_filter_state_t` and should never be accessed directly. After
 * initialisation, all access to this memory occurs exclusively through the BFP
 * structures owned by the AEC state.
 *
 * @ingroup aec_memory_pool
 */
typedef struct {
    /** Memory pointed to by aec_shared_filter_state_t::y and aec_shared_filter_state_t::Y*/
    int32_t mic_input_frame[AEC_MAX_Y_CHANNELS][AEC_PROC_FRAME_LENGTH + AEC_FFT_PADDING];
    /** Memory pointed to by aec_shared_filter_state_t::x and aec_shared_filter_state_t::X. Also reused for main filter
     * aec_filter_state_t::T*/
    int32_t ref_input_frame[AEC_MAX_X_CHANNELS][AEC_PROC_FRAME_LENGTH + AEC_FFT_PADDING];
    /** Memory pointed to by aec_shared_filter_state_t::prev_y*/
    int32_t mic_prev_samples[AEC_MAX_Y_CHANNELS][AEC_PROC_FRAME_LENGTH - AEC_FRAME_ADVANCE];
    /** Memory pointed to by aec_shared_filter_state_t::prev_x*/
    int32_t ref_prev_samples[AEC_MAX_X_CHANNELS][AEC_PROC_FRAME_LENGTH - AEC_FRAME_ADVANCE];
    /** Memory pointed to by main filter aec_filter_state_t::H_hat, aec_shared_filter_state_t::X_fifo, main filter
     * aec_filter_state_t::X_fifo_1d and shadow filter aec_filter_state_t::X_fifo_1d*/
    complex_s32_t phase_pool_H_hat_X_fifo[((AEC_MAX_Y_CHANNELS*AEC_MAX_X_CHANNELS*AEC_MAIN_FILTER_PHASES) + (AEC_MAX_X_CHANNELS*AEC_MAIN_FILTER_PHASES)) * AEC_FD_FRAME_LENGTH];
    /** Memory pointed to by main filter aec_filter_state_t::Error and aec_filter_state_t::error*/
    complex_s32_t Error[AEC_MAX_Y_CHANNELS][AEC_FD_FRAME_LENGTH];
    /** Memory pointed to by main filter aec_filter_state_t::Y_hat and aec_filter_state_t::y_hat*/
    complex_s32_t Y_hat[AEC_MAX_Y_CHANNELS][AEC_FD_FRAME_LENGTH];
    /** Memory pointed to by main_filter aec_filter_state_t::X_energy*/
    int32_t X_energy[AEC_MAX_X_CHANNELS][AEC_FD_FRAME_LENGTH];
    /** Memory pointed to by aec_shared_filter_state_t::sigma_XX*/
    int32_t sigma_XX[AEC_MAX_X_CHANNELS][AEC_FD_FRAME_LENGTH];
    /** Memory pointed to by main filter aec_filter_state_t::inv_X_energy*/
    int32_t inv_X_energy[AEC_MAX_X_CHANNELS][AEC_FD_FRAME_LENGTH];
    /** Memory pointed to by main filter aec_filter_state_t::overlap*/
    int32_t overlap[AEC_MAX_Y_CHANNELS][AEC_UNUSED_TAPS_PER_PHASE*2];
}aec_memory_pool_t;

/**
 * @brief aec_shadow_filt_memory_pool_t
 *
 * Memory pool for AEC shadow filter.
 *
 * This pool provides contiguous storage for all BFP (block floating-point from ``lib_xcore_math``) structures used by the AEC shadow filter (`aec_filter_state_t`).
 * The `aec_init()` function initializes the BFP structures in the AEC state structures to point to
 * memory buffers from this pool during AEC initialisation.
 *
 * The memory pool allocates storage based on AEC compile-time configuration parameters:
 * - @ref AEC_MAX_Y_CHANNELS
 * - @ref AEC_MAX_X_CHANNELS
 * - @ref AEC_MAIN_FILTER_PHASES
 * - @ref AEC_SHADOW_FILTER_PHASES
 *
 * The same pool can be used to initialize AEC for any runtime configuration (passed as arguments to `aec_init()`)
 * that is a subset of the compile-time configuration (See @ref aec_phase_pool_capacity).
 *
 * @note
 * This structure exists to own memory, not to describe layout.
 * The memory pool acts as a linear allocation arena used by `aec_init()` to
 * initialise BFP structures in the AEC filter state structures. Memory is assigned
 * sequentially from the pool based on the runtime configuration (number of
 * channels and filter phases), and does not have a fixed or semantic mapping to
 * the individual fields of this struct.
 * The named members of this struct exist only to reserve sufficient contiguous
 * storage at compile time. They must not be interpreted as backing specific
 * components of `aec_filter_state_t`/`aec_shared_filter_state_t` and should never be accessed directly. After
 * initialisation, all access to this memory occurs exclusively through the BFP
 * structures owned by the AEC state.
 *
 * @ingroup aec_memory_pool
 */
typedef struct {
    /** Memory pointed to by shadow filter aec_filter_state_t::H_hat*/
    complex_s32_t phase_pool_H_hat[AEC_MAX_Y_CHANNELS * AEC_MAX_X_CHANNELS * AEC_SHADOW_FILTER_PHASES * AEC_FD_FRAME_LENGTH];
    /** Memory pointed to by shadow filter aec_filter_state_t::Error and aec_filter_state_t::error*/
    complex_s32_t Error[AEC_MAX_Y_CHANNELS][AEC_FD_FRAME_LENGTH];
    /** Memory pointed to by shadow filter aec_filter_state_t::Y_hat and aec_filter_state_t::y_hat*/
    complex_s32_t Y_hat[AEC_MAX_Y_CHANNELS][AEC_FD_FRAME_LENGTH];
    /** Memory pointed to by shadow filter aec_filter_state_t::T*/
    complex_s32_t T[AEC_MAX_X_CHANNELS][AEC_FD_FRAME_LENGTH];
    /** Memory pointed to by shadow_filter aec_filter_state_t::X_energy*/
    int32_t X_energy[AEC_MAX_X_CHANNELS][AEC_FD_FRAME_LENGTH];
    /** Memory pointed to by shadow_filter aec_filter_state_t::inv_X_energy*/
    int32_t inv_X_energy[AEC_MAX_X_CHANNELS][AEC_FD_FRAME_LENGTH];
    /** Memory pointed to by shadow filter aec_filter_state_t::overlap*/
    int32_t overlap[AEC_MAX_Y_CHANNELS][AEC_UNUSED_TAPS_PER_PHASE*2];
}aec_shadow_filt_memory_pool_t;
#endif
