// Copyright 2024-2025 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <string.h>
#include <stdlib.h>
#include <xcore/assert.h>
#include <debug_print.h>
#include "cmds.h" // Autogenerated
#include "cmd_offsets.h" // Autogenerated
#include "stages/crossfader_stereo.h"
#include <stdio.h>
#include "print.h"
#include "control/signal_chain.h"

void crossfader_stereo_process(int32_t **input, int32_t **output, void *app_data_state)
{
    crossfader_stereo_state_t *state = app_data_state;

    int32_t *in1_L = input[0];
    int32_t *in1_R = input[1];
    int32_t *in2_L = input[2];
    int32_t *in2_R = input[3];
    int32_t *out_L = output[0];
    int32_t *out_R = output[1];

    int j = 0;
    do
    {
        int32_t gain_1 = adsp_slew_gain(&state->cfs.gain_1);
        int32_t gain_2 = adsp_slew_gain(&state->cfs.gain_2);
        *out_L++ = adsp_crossfader(*in1_L++, *in2_L++, gain_1, gain_2, 31);
        *out_R++ = adsp_crossfader(*in1_R++, *in2_R++, gain_1, gain_2, 31);
    } while (++j < state->frame_size);
}


void crossfader_stereo_init(module_instance_t* instance, adsp_bump_allocator_t* allocator, uint8_t id, int n_inputs, int n_outputs, int frame_size)
{
    crossfader_stereo_state_t *state = instance->state;
    crossfader_stereo_config_t *config = instance->control.config;

    memset(state, 0, sizeof(crossfader_stereo_state_t));
    state->n_inputs = n_inputs;
    xassert(n_inputs == 4 && "Stereo crossfader must have 2 stereo inputs");

    state->frame_size = frame_size;
    xassert(n_outputs == 2 && "Stereo crossfader should only have two outputs");
    state->n_outputs = n_outputs;

    state->cfs.gain_1 = adsp_slew_gain_init(config->gains[0], 7);
    state->cfs.gain_2 = adsp_slew_gain_init(config->gains[1], 7);
}

void crossfader_stereo_control(void *module_state, module_control_t *control)
{
    crossfader_stereo_state_t *state = module_state;
    crossfader_stereo_config_t *config = control->config;

    if(control->config_rw_state == config_write_pending)
    {
        // Finish the write by updating the working copy with the new config
        state->cfs.gain_1.target_gain = config->gains[0];
        state->cfs.gain_2.target_gain = config->gains[1];
        control->config_rw_state = config_none_pending;
    }
    else if(control->config_rw_state == config_read_pending)
    {
        config->gains[0] = state->cfs.gain_1.target_gain;
        config->gains[1] = state->cfs.gain_2.target_gain;
        control->config_rw_state = config_read_updated;
    }
    else
    {
        // nothing to do.
    }
}

