void irreference_dump_internal (t_irreference *x, t_symbol *sym, short argc, t_atom *argv)
{
    double *out_mem;

    t_buffer_write_error error;
    t_atom_long in_chan = 1;
    t_symbol *buffer = 0;

    AH_UIntPtr fft_size = x->fft_size;
    AH_UIntPtr mem_size;

    // Get arguments

    if (!argc)
    {
        object_error ((t_object *) x, "no arguments for dump message");
        return;
    }

    in_chan = argc > 1 ? atom_getlong(argv++) : 1;
    buffer = atom_getsym(argv++);

    // Range check

    if (in_chan < 1 || in_chan > x->current_num_active_ins)
    {
        object_error((t_object *) x, "input channel %ld out of range", in_chan);
        return;
    }

    // Decrement input channel (reference to zero)

    in_chan--;

    if (!fft_size)
    {
        object_error ((t_object *) x, "no stored impulse responses - you may still be recording");
        return;
    }

    // Get and check memory

    out_mem = (double *) access_mem_swap(&x->out_mem, &mem_size) + (in_chan * fft_size);

    if (mem_size < fft_size)
    {
        object_error((t_object *) x, "storage memory is not large enough");
        return;
    }

    // Write to buffer

    error = buffer_write(buffer, out_mem, fft_size, x->write_chan - 1, x->resize, x->sample_rate, 1.);
    buffer_write_error((t_object *) x, buffer, error);

    // Free temporary memory
}
void irreference_extract_internal (t_irreference *x, t_symbol *sym, short argc, t_atom *argv)
{
    double *rec_mem;

    t_buffer_write_error error;
    t_atom_long in_chan = 1;
    t_symbol *buffer = 0;

    AH_SIntPtr rec_length = x->current_length;

    AH_UIntPtr fft_size = x->fft_size;
    AH_UIntPtr mem_size;

    rec_mem = access_mem_swap(&x->rec_mem, &mem_size);

    // Get arguments

    if (!argc)
    {
        object_error ((t_object *) x, "no arguments for extract message");
        return;
    }

    in_chan = argc > 1 ? atom_getlong(argv++) : 1;
    buffer = atom_getsym(argv++);

    // Range check

    if (in_chan < 1 || in_chan > x->current_num_active_ins)
    {
        object_error((t_object *) x, "input channel %ld out of range", in_chan);
        return;
    }

    // Decrement input channel (reference to zero)

    in_chan--;

    if (!fft_size)
    {
        object_error ((t_object *) x, "no stored impulse responses - you may still be recording");
        return;
    }

    // Write to buffer

    error = buffer_write(buffer, rec_mem + rec_length * in_chan, rec_length, x->write_chan - 1, x->resize, x->sample_rate, 1.);
    buffer_write_error((t_object *) x, buffer, error);
}
void irmeasure_process(t_irmeasure *x, t_symbol *sym, short argc, t_atom *argv)
{
    FFT_SETUP_D fft_setup;

    FFT_SPLIT_COMPLEX_D spectrum_1;
    FFT_SPLIT_COMPLEX_D spectrum_2;
    FFT_SPLIT_COMPLEX_D spectrum_3;

    void *measurement_rec;
    void *rec_mem;
    double *excitation_sig;
    double *out_buf;
    double *out_mem;
    float *filter_in;

    t_symbol *filter = filter_retriever(x->deconvolve_filter_specifier);

    double filter_specifier[HIRT_MAX_SPECIFIER_ITEMS];
    double range_specifier[HIRT_MAX_SPECIFIER_ITEMS];

    double test_pow;
    double max_pow;
    double sample_rate = x->sample_rate;
    double deconvolve_phase = phase_retriever(x->deconvolve_phase);

    long deconvolve_mode = x->deconvolve_mode;
    long bandlimit = x->measure_mode == SWEEP ? x->bandlimit : 0;

    AH_SIntPtr rec_length = x->T2;
    AH_SIntPtr gen_length = 0;
    AH_SIntPtr filter_length = buffer_length(filter);

    AH_UIntPtr fft_size;
    AH_UIntPtr fft_size_log2;
    AH_UIntPtr mem_size;
    AH_UIntPtr i;

    t_ess sweep_params;
    t_mls max_length_params;
    t_noise_params noise_params;

    switch (x->measure_mode)
    {
        case SWEEP:
            ess_params(&sweep_params, x->sweep_params.rf1, x->sweep_params.rf2, x->sweep_params.fade_in, x->sweep_params.fade_out, x->sweep_params.RT, x->sweep_params.sample_rate, x->inv_amp ? x->sweep_params.amp : 1, x->amp_curve);
            gen_length = ess_get_length(&sweep_params);
            break;

        case MLS:

            mls_params(&max_length_params, x->max_length_params.order, x->inv_amp ? x->max_length_params.amp : 1);
            gen_length = mls_get_length(&max_length_params);

            break;

        case NOISE:

            coloured_noise_params(&noise_params, x->noise_params.mode, x->noise_params.fade_in, x->noise_params.fade_out, x->noise_params.RT, x->noise_params.sample_rate,   x->inv_amp ? x->noise_params.amp : 1);
            gen_length = coloured_noise_get_length(&noise_params);
            break;
    }

    // Check and calculate lengths

    fft_size = calculate_fft_size(rec_length + gen_length, &fft_size_log2);

    // Allocate Temporary Memory

    fft_setup = hisstools_create_setup_d(fft_size_log2);

    excitation_sig = (double *)  malloc(gen_length * sizeof(double));

    spectrum_1.realp = ALIGNED_MALLOC((sizeof(double) * fft_size * 4));
    spectrum_1.imagp = spectrum_1.realp + (fft_size >> 1);
    spectrum_2.realp = spectrum_1.imagp + (fft_size >> 1);
    spectrum_2.imagp = spectrum_2.realp + (fft_size >> 1);
    spectrum_3.realp = spectrum_2.imagp + (fft_size >> 1);
    spectrum_3.imagp = spectrum_3.realp + fft_size;

    filter_in = filter_length ? (float *) ALIGNED_MALLOC(sizeof(float) * filter_length) : 0;

    if (!fft_setup || !excitation_sig || !spectrum_1.realp || (filter_length && !filter_in))
    {
        object_error ((t_object *) x, "could not allocate temporary memory for processing");

        hisstools_destroy_setup_d(fft_setup);
        free(excitation_sig);
        ALIGNED_FREE(spectrum_1.realp);
        ALIGNED_FREE(filter_in);

        return;
    }

    // Allocate output memory and get record memory

    rec_mem = access_mem_swap(&x->rec_mem, &mem_size);
    out_mem = grow_mem_swap(&x->out_mem, fft_size * x->current_num_active_ins * sizeof(double), fft_size * x->current_num_active_ins);

    if (!out_mem)
    {
        object_error ((t_object *) x, "could not allocate memory for output storage");
        free(excitation_sig);
        hisstools_destroy_setup_d(fft_setup);
        return;
    }

    // Generate Signal

    switch (x->measure_mode)
    {
        case SWEEP:
            ess_gen(&sweep_params, excitation_sig, true);
            break;

        case MLS:
            mls_gen(&max_length_params, excitation_sig, true);
            break;

        case NOISE:
            coloured_noise_gen(&noise_params, excitation_sig, true);
            break;
    }

    // Transform excitation signal into complex spectrum 2

    time_to_halfspectrum_double(fft_setup, excitation_sig, gen_length, spectrum_2, fft_size);

    if (bandlimit)
    {
        // Calculate standard filter for bandlimited deconvolution (sweep * inv sweep)

        ess_igen(&sweep_params, excitation_sig, INVERT_ALL, true);
        time_to_halfspectrum_double(fft_setup, excitation_sig, gen_length, spectrum_3, fft_size);
        convolve(spectrum_3, spectrum_2, fft_size, SPECTRUM_REAL);

        // Calculate full power spectrum from half spectrum - convert filter to have the required phase

        power_full_spectrum_from_half_spectrum(spectrum_3, fft_size);
        variable_phase_from_power_spectrum(fft_setup, spectrum_3, fft_size, deconvolve_phase, true);

        // Convert back to real format

        spectrum_3.imagp[0] = spectrum_3.realp[fft_size >> 1];
    }
    else
    {
        // Find maximum power to scale

        for (i = 1, max_pow = 0; i < (fft_size >> 1); i++)
void irreference_process (t_irreference *x, t_symbol *sym, short argc, t_atom *argv)
{
    FFT_SETUP_D fft_setup;

    FFT_SPLIT_COMPLEX_D spectrum_1;
    FFT_SPLIT_COMPLEX_D spectrum_2;
    FFT_SPLIT_COMPLEX_D spectrum_3;
    FFT_SPLIT_COMPLEX_D spectrum_4;

    void *rec_mem1;
    void *rec_mem2;
    double *out_mem;
    double *out_buf;
    float *filter_in;

    t_symbol *filter = filter_retriever(x->deconvolve_filter_specifier);

    double filter_specifier[HIRT_MAX_SPECIFIER_ITEMS];
    double range_specifier[HIRT_MAX_SPECIFIER_ITEMS];

    double sample_rate = x->sample_rate;
    double deconvolve_phase = phase_retriever(x->deconvolve_phase);
    double deconvolve_delay;

    long deconvolve_mode = deconvolve_mode = x->deconvolve_mode;
    long smoothing_on = x->num_smooth;

    AH_SIntPtr alloc_rec_length = x->T;
    AH_SIntPtr rec_length = x->current_length;
    AH_SIntPtr filter_length = buffer_length(filter);

    AH_UIntPtr fft_size;
    AH_UIntPtr fft_size_log2;
    AH_UIntPtr mem_size;
    AH_UIntPtr i;

    // Sanity check

    if (!rec_length)
        return;

    // Check and calculate lengths

    fft_size = calculate_fft_size(rec_length * 2, &fft_size_log2);
    deconvolve_delay = delay_retriever(x->deconvolve_delay, fft_size, sample_rate);

    // Allocate Temporary Memory

    fft_setup = hisstools_create_setup_d(fft_size_log2);

    spectrum_1.realp = ALIGNED_MALLOC((sizeof(double) * fft_size * 4));
    spectrum_1.imagp = spectrum_1.realp + (fft_size >> 1);
    spectrum_2.realp = spectrum_1.imagp + (fft_size >> 1);
    spectrum_2.imagp = spectrum_2.realp + (fft_size >> 1);
    spectrum_3.realp = spectrum_2.imagp + (fft_size >> 1);
    spectrum_3.imagp = spectrum_3.realp + fft_size;

    filter_in = filter_length ? ALIGNED_MALLOC(sizeof(float *) * filter_length) : 0;

    if (smoothing_on)
    {
        spectrum_4.realp = malloc(sizeof(double) * 2 * fft_size);
        spectrum_4.imagp = spectrum_4.realp + fft_size;
    }
    else
        spectrum_4.realp = 0;

    if (!fft_setup || !spectrum_1.realp || (smoothing_on && !spectrum_4.realp) || (filter_length && !filter_in))
    {
        object_error ((t_object *) x, "could not allocate temporary memory for processing");

        hisstools_destroy_setup_d(fft_setup);
        ALIGNED_FREE(spectrum_1.realp);
        ALIGNED_FREE(filter_in);
        free(spectrum_4.realp);

        return;
    }

    x->fft_size = fft_size;

    // Allocate output memory and get record memory

    rec_mem1 = access_mem_swap(&x->rec_mem, &mem_size);
    out_mem = grow_mem_swap(&x->out_mem, fft_size * x->current_num_active_ins * sizeof(double), fft_size);

    if (!out_mem)
    {
        object_error ((t_object *) x, "could not allocate memory for output storage");
        free(spectrum_1.realp);
        hisstools_destroy_setup_d(fft_setup);
        return;
    }

    // Transform reference into spectrum 2 - [smooth]

    time_to_halfspectrum_double(fft_setup, rec_mem1, rec_length, spectrum_2, fft_size);
    if (smoothing_on)
        irreference_smooth(fft_setup, spectrum_2, spectrum_4, x->smooth_mode, fft_size, x->num_smooth > 1 ? x->smooth[0] : 0., x->num_smooth > 1 ? x->smooth[1] : x->smooth[0]);

    // Fill deconvolution filter specifiers - read filter from buffer (if specified) - make deconvolution filter - delay filter

    fill_power_array_specifier(filter_specifier, x->deconvolve_filter_specifier, x->deconvolve_num_filter_specifiers);
    fill_power_array_specifier(range_specifier, x->deconvolve_range_specifier, x->deconvolve_num_range_specifiers);
    buffer_read(filter, 0, filter_in, fft_size);
    make_deconvolution_filter(fft_setup, spectrum_2, spectrum_3, filter_specifier, range_specifier, 0, filter_in, filter_length, fft_size, SPECTRUM_REAL, deconvolve_mode, deconvolve_phase, sample_rate);
    delay_spectrum(spectrum_3, fft_size, SPECTRUM_REAL, deconvolve_delay);

    // Deconvolve each input

    for (i = 0; i < (AH_UIntPtr) x->current_num_active_ins; i++)
    {
        // Get current input and output buffers

        rec_mem2 = (double *) rec_mem1 + ((i + 1) * alloc_rec_length);
        out_buf = out_mem + (i * fft_size);

        // Do transform into spectrum_1 - [smooth] - deconvolve - [delay] - transform back

        time_to_halfspectrum_double(fft_setup, rec_mem2, rec_length, spectrum_1, fft_size);
        if (smoothing_on)
            irreference_smooth(fft_setup, spectrum_1, spectrum_4, x->smooth_mode, fft_size, x->num_smooth > 1 ? x->smooth[0] : 0., x->num_smooth > 1 ? x->smooth[1] : x->smooth[0]);
        deconvolve_with_filter(spectrum_1, spectrum_2, spectrum_3, fft_size, SPECTRUM_REAL);
        spectrum_to_time(fft_setup, out_buf, spectrum_1, fft_size, SPECTRUM_REAL);
    }

    // Free Memory

    hisstools_destroy_setup_d(fft_setup);
    ALIGNED_FREE(spectrum_1.realp);
    ALIGNED_FREE(filter_in);
    free(spectrum_4.realp);

    // Done

    outlet_bang(x->process_done);
}