void bufreverse_process_internal(t_bufreverse *x, t_symbol *sym, short argc, t_atom *argv)
{
    t_symbol *target = atom_getsym(argv++);
    t_symbol *source = atom_getsym(argv++);

    float *temp1;
    double *temp2;

    t_buffer_write_error error;

    AH_SIntPtr full_length = buffer_length(source);
    AH_SIntPtr i;

    double sample_rate = 0;
    t_atom_long read_chan = x->read_chan - 1;

    // Check source buffer

    if (buffer_check((t_object *) x, source, read_chan))
        return;
    sample_rate = buffer_sample_rate(source);

    // Allocate Memory

    temp1 = (float *) ALIGNED_MALLOC(full_length * (sizeof(double) + sizeof(float)));
    temp2 = (double *) (temp1 + full_length);

    // Check momory allocation

    if (!temp1)
    {
        object_error((t_object *)x, "could not allocate temporary memory for processing");
        free(temp1);
        return;
    }

    // Read from buffer

    buffer_read(source, read_chan, (float *) temp1, full_length);

    // Copy to double precision version

    for (i = 0; i < full_length; i++)
         temp2[i] = temp1[full_length - i - 1];

    // Copy out to buffer

    error = buffer_write(target, temp2, full_length, x->write_chan - 1, x->resize, sample_rate, 1.);
    buffer_write_error((t_object *)x, target, error);

    // Free Resources

    ALIGNED_FREE(temp1);

    if (!error)
        outlet_bang(x->process_done);
}
void irextract_mls (t_irextract *x, t_symbol *sym, long argc, t_atom *argv)
{
	double sample_rate;
	double out_length = 0;
	
	t_atom_long num_channels = 1;
	t_atom_long order = 18;
	
	t_symbol *rec_buffer = 0;

	// Load parameters

	if (argc > 0)
	{
		rec_buffer = atom_getsym(argv++);
		sample_rate = buffer_sample_rate(rec_buffer);
	}
	if (argc > 1)
		order = atom_getlong(argv++);
	if (argc > 2)
		num_channels = atom_getlong(argv++);
	if (argc > 3)
		out_length = atom_getfloat(argv++);
	
	// Check parameters
	
	if (!rec_buffer)
	{
		object_error((t_object *)x, "no buffer given");
		return;
	}
	
	order = (t_atom_long) irextract_param_check(x, "order", (double) order, 1, 24);
	num_channels = (t_atom_long) irextract_param_check(x, "number of channels", (double) num_channels, 1, HIRT_MAX_MEASURE_CHANS);
	x->out_length = irextract_param_check(x, "output length", out_length, 0., HUGE_VAL) / 1000.;

	// Process
	
	x->measure_mode = MLS;
	mls_params(&x->max_length_params, (long) order, db_to_a(x->amp));
	irextract_process(x, rec_buffer, num_channels, sample_rate);
}
short buffer_multiple_names(t_object *x, t_symbol **in_bufs, t_symbol **out_bufs, AH_SIntPtr *lengths, short argc, t_atom *argv, t_atom_long read_chan, t_atom_long write_chan, long in_place, short max_bufs, AH_SIntPtr *overall_len_ret, AH_SIntPtr *max_len_ret, double *sample_rate_ret)
{
    AH_SIntPtr overall_length = 0;
    AH_SIntPtr max_length = 0;
    AH_SIntPtr new_length;
    short i;

    double sample_rate = 0.0;
    double new_sample_rate;

    if (!in_place)
    {
        if (argc % 2)
        {
            object_error((t_object *) x, "target buffer with no matching input buffer");
            return 0;
        }

        argc /= 2;
    }

    if (argc > max_bufs)
        argc = max_bufs;

    if (!argc)
    {
        object_error(x, "no buffers specified");
        return 0;
    }

    for (i = 0; i < argc; i++)
    {
        if (atom_gettype(argv + i) != A_SYM)
        {
            object_error(x, "name of buffer expected, but number given");
            return 0;
        }

        if (buffer_check(x, atom_getsym(argv + i), write_chan))
            return 0;

        if (in_place)
        {
            new_length = buffer_length (atom_getsym(argv + i));
            new_sample_rate = buffer_sample_rate(atom_getsym(argv + i));

            if (buffer_check(x, atom_getsym(argv + i), read_chan))
                return 0;
        }
        else
        {
            new_length = buffer_length (atom_getsym(argv + i + argc));
            new_sample_rate = buffer_sample_rate(atom_getsym(argv + i + argc));

            if (buffer_check(x, atom_getsym(argv + i + argc), read_chan))
                return 0;
        }

        if (new_length == 0)
        {
            object_error(x, "buffer %s has zero length ", atom_getsym(argv + i)->s_name);
            return 0;
        }

        // Store name and length

        out_bufs[i] = atom_getsym(argv + i);
        lengths[i] = new_length;

        if (in_place)
            in_bufs[i] = atom_getsym(argv + i);
        else
            in_bufs[i] = atom_getsym(argv + i + argc);

        if (new_length > max_length)
            max_length = new_length;

        overall_length += new_length;

        // Check sample rates

        if ((sample_rate != 0.0 && sample_rate != new_sample_rate) || new_sample_rate == 0.0)
            object_warn(x, "sample rates do not match for all source buffers");
        else
            sample_rate = new_sample_rate;
    }

    *overall_len_ret = overall_length;
    *max_len_ret = max_length;
    *sample_rate_ret = sample_rate;

    return argc;
}
void bufconvolve_process_internal (t_bufconvolve *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;

	double *out_buf;
	float *in_temp;
	float *filter_in;
	
	AH_Boolean convolve_mode = sym == gensym("convolve") ? true : false;

	t_symbol *target = atom_getsym(argv++);
	t_symbol *source_1 = atom_getsym(argv++);
	t_symbol *source_2 = atom_getsym(argv++);
	t_symbol *filter = filter_retriever(x->deconvolve_filter_specifier);
	
	double filter_specifier[HIRT_MAX_SPECIFIER_ITEMS];
	double range_specifier[HIRT_MAX_SPECIFIER_ITEMS];
	
	double time_mul = atom_getfloat(argv++);
	double sample_rate = buffer_sample_rate(source_1); 
	double deconvolve_phase = phase_retriever(x->deconvolve_phase);
	double deconvolve_delay;
		
	AH_SIntPtr source_length_1 = buffer_length(source_1);
	AH_SIntPtr source_length_2 = buffer_length(source_2);
	AH_SIntPtr filter_length = buffer_length(filter);
	
	AH_UIntPtr fft_size;
	AH_UIntPtr fft_size_log2; 
	
	long deconvolve_mode = x->deconvolve_mode;
	t_buffer_write_error error;
	
	// Check input buffers
	
	if (buffer_check((t_object *) x, source_1) || buffer_check((t_object *) x, source_2))
		return;
	
	// Check sample rates
	
	if (sample_rate != buffer_sample_rate(source_2))
		object_warn((t_object *) x, "sample rates do not match");
	
	// Check and calculate lengths
	
	if (convolve_mode == true)
		fft_size = (AH_UIntPtr) ((source_length_1 + source_length_2) * time_mul);
	else
		fft_size = (AH_UIntPtr) (source_length_1 < source_length_2 ? source_length_2 * time_mul : source_length_1 * time_mul);
		
	fft_size = calculate_fft_size(fft_size, &fft_size_log2);
	deconvolve_delay = delay_retriever(x->deconvolve_delay, fft_size, sample_rate);

	if (fft_size < 8)
	{
		object_error((t_object *) x, "input buffers are too short, or have no length");
		return;
	}
	
	// Allocate Memory (use pointer aliasing where possible for efficiency)
	
	fft_setup = hisstools_create_setup_d(fft_size_log2);

	spectrum_1.realp = ALIGNED_MALLOC(sizeof(double) * fft_size * (convolve_mode == true ? 3 : 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 = convolve_mode == true ? 0 : spectrum_3.realp + fft_size;
	
	filter_in = filter_length ? ALIGNED_MALLOC(sizeof(float *) * filter_length) : 0; 
	
	out_buf = spectrum_2.realp;
	in_temp = (float *) spectrum_3.realp;
	
	// Check memory allocations
	
	if (!fft_setup || !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);
		ALIGNED_FREE(spectrum_1.realp);
		ALIGNED_FREE(filter_in);
		
		return;
	}

	// Get inputs - convert to frequency domain
	
	buffer_read(source_1, x->read_chan - 1, in_temp, source_length_1);
	time_to_halfspectrum_float(fft_setup, in_temp, source_length_1, spectrum_1, fft_size);
	buffer_read(source_2, x->read_chan - 1, in_temp, source_length_2);
	time_to_halfspectrum_float(fft_setup, in_temp, source_length_2, spectrum_2, fft_size);		
		
	// Do deconvolution or convolution
	
	if (convolve_mode == true)
		convolve(spectrum_1, spectrum_2, fft_size, SPECTRUM_REAL);	
	else
	{
		// Fill deconvolution filter specifiers - load filter from buffer (if specified) - deconvolve
		
		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);
		deconvolve(fft_setup, spectrum_1, spectrum_2, spectrum_3, filter_specifier, range_specifier, 0.0, filter_in, filter_length, fft_size, SPECTRUM_REAL, deconvolve_mode, deconvolve_phase, deconvolve_delay, sample_rate);
	}
	
	// Convert to time domain - copy out to buffer
	
	spectrum_to_time(fft_setup, out_buf, spectrum_1, fft_size, SPECTRUM_REAL);	
	error = buffer_write(target, out_buf, (convolve_mode == true ? source_length_1 + source_length_2 - 1 : fft_size), x->write_chan - 1, x->resize, sample_rate, 1.);
	buffer_write_error((t_object *) x, target, error);
	
	// Free resources
	
	hisstools_destroy_setup_d(fft_setup);
	ALIGNED_FREE(spectrum_1.realp);
	ALIGNED_FREE(filter_in);
	
	if (!error)
		outlet_bang(x->process_done);
}
void irphase_process_internal (t_irphase *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;

	float *in;
	float *filter_in;
	double *out_buf;
	
	t_symbol *filter = filter_retriever(x->deconvolve_filter_specifier);
	t_symbol *target = atom_getsym(argv++);
	t_symbol *source = atom_getsym(argv++);
	
	double filter_specifier[HIRT_MAX_SPECIFIER_ITEMS];
	double range_specifier[HIRT_MAX_SPECIFIER_ITEMS];
	
	double phase = atom_getfloat(argv++);
	double time_mul = atom_getfloat(argv++);	
	double sample_rate = buffer_sample_rate(source);
	double deconvolve_delay;
	double deconvolve_phase;
	
	t_phase_type mode = (t_phase_type) atom_getlong(argv++);
	
	AH_UIntPtr fft_size;
	AH_UIntPtr fft_size_log2;
	AH_UIntPtr i;
	
	t_buffer_write_error error;
	long deconvolve_mode;
	
	// Get input buffer lengths
	
	AH_SIntPtr source_length_1 = buffer_length(source);
	AH_SIntPtr filter_length = buffer_length(filter);
	AH_SIntPtr max_length = source_length_1;
	
	// Check input buffers
	
	if (buffer_check((t_object *) x, source))
		return;
	
	// Calculate fft size
	
	time_mul = time_mul == 0. ? 1 : time_mul;		

	if (time_mul < 1)
	{
		object_warn((t_object *) x, " time multiplier cannot be less than 1 (using 1)");
		time_mul = 1;
	}
	
	fft_size = calculate_fft_size((long) (max_length * time_mul), &fft_size_log2);

	if (fft_size < 8)
	{
		object_error((t_object *) x, "buffers are too short, or have no length");
		return;
	}
	
	deconvolve_mode = x->deconvolve_mode;
	deconvolve_phase = phase_retriever(x->deconvolve_phase);
	deconvolve_delay = delay_retriever(x->deconvolve_delay, fft_size, sample_rate);
	
	// Allocate momory

	fft_setup = hisstools_create_setup_d(fft_size_log2);
	
	spectrum_1.realp = ALIGNED_MALLOC(sizeof(double) * fft_size * (mode == MODE_ALLPASS ? 6 : 3));
	spectrum_1.imagp = spectrum_1.realp + fft_size;
	spectrum_2.realp = spectrum_1.imagp + fft_size;
	spectrum_2.imagp = mode == MODE_ALLPASS ? spectrum_2.realp + fft_size : 0;
	spectrum_3.realp = mode == MODE_ALLPASS ? spectrum_2.imagp + fft_size : 0;
	spectrum_3.imagp = mode == MODE_ALLPASS ? spectrum_3.realp + fft_size : 0;
	
	filter_in = filter_length ? ALIGNED_MALLOC(sizeof(float *) * filter_length) : 0; 

	out_buf = mode == MODE_ALLPASS ? spectrum_3.realp : spectrum_2.realp;
	in = (float *) out_buf;

	if (!spectrum_1.realp || !fft_setup || (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);
		
		return;
	}
	
	// Get input - convert to frequency domain - get power spectrum - convert phase
	
	buffer_read(source, x->read_chan - 1, in, fft_size);
	time_to_spectrum_float(fft_setup, in, source_length_1, spectrum_1, fft_size);
	power_spectrum(spectrum_1, fft_size, SPECTRUM_FULL);
	variable_phase_from_power_spectrum(fft_setup, spectrum_1, fft_size, phase, false);			

	if (mode == MODE_ALLPASS)
	{
		// Copy minimum phase spectrum to spectrum_2 
		
		for (i = 0; i < fft_size; i++) 
		{
			spectrum_2.realp[i] = spectrum_1.realp[i];
			spectrum_2.imagp[i] = spectrum_1.imagp[i]; 
			
		}
		
		// Get input again
	
		time_to_spectrum_float(fft_setup, in, source_length_1, spectrum_1, fft_size);
		
		// Fill deconvolution filter specifiers - read filter from buffer (if specified) - deconvolve input by minimum phase spectrum
		
		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);
		deconvolve(fft_setup, spectrum_1, spectrum_2, spectrum_3, filter_specifier, range_specifier, 0, filter_in, filter_length, fft_size, SPECTRUM_FULL, deconvolve_mode, deconvolve_phase, deconvolve_delay, sample_rate);
	}
			
	// Convert to time domain - copy out to buffer
	
	spectrum_to_time(fft_setup, out_buf, spectrum_1, fft_size, SPECTRUM_FULL);
	error = buffer_write(target, out_buf, fft_size, x->write_chan - 1, x->resize, sample_rate, 1);
	buffer_write_error((t_object *) x, target, error);
	
	// Free memory
	
	hisstools_destroy_setup_d(fft_setup);
	ALIGNED_FREE(spectrum_1.realp);
	ALIGNED_FREE(filter_in);
	
	if (!error)
		outlet_bang(x->process_done);
}
void ircropfade_process_internal(t_ircropfade *x, t_symbol *sym, short argc, t_atom *argv)
{
    // Load arguments

    t_symbol *target = atom_getsym(argv++);
    t_symbol *source = atom_getsym(argv++);
    t_atom_long crop1 = atom_getlong(argv++);
    t_atom_long crop2 = atom_getlong(argv++);
    double fade_start = atom_getfloat(argv++);
    double in_length = atom_getfloat(argv++);
    double fade_end = atom_getfloat(argv++);
    double out_length = atom_getfloat(argv++);

    // Set fade variables

    double fade_in_lo = fade_start - 1;
    double fade_in_hi = in_length > 0 ? fade_start + in_length : fade_start;
    double fade_out_lo = fade_end;
    double fade_out_hi = out_length > 0 ? fade_end - out_length : fade_end - 1;
    double fade_in_recip = 1. / (fade_in_hi - fade_in_lo);
    double fade_out_recip = 1. / (fade_out_hi - fade_out_lo);

    float *temp1;
    double *temp2;

    t_buffer_write_error error;

    AH_SIntPtr full_length = buffer_length(source);
    AH_SIntPtr final_length;
    AH_SIntPtr i;

    t_atom_long read_chan = x->read_chan - 1;

    double sample_rate = 0;

    // Check source buffer

    if (buffer_check((t_object *) x, source, read_chan))
        return;
    sample_rate = buffer_sample_rate(source);

    crop1 = crop1 < 0 ? 0 : crop1;
    crop2 = crop2 < 0 ? 0 : crop2;
    crop1 = crop1 > full_length - 1 ? full_length - 1: crop1;
    crop2 = crop2 > full_length ? full_length : crop2;

    if (crop1 >= crop2)
        return;

    final_length = crop2 - crop1;

    // Allocate Memory

    temp1 = (float *) ALIGNED_MALLOC(full_length  * sizeof(float) + final_length * sizeof(double));
    temp2 = (double *) (temp1 + full_length);

    // Check momory allocation

    if (!temp1)
    {
        object_error((t_object *)x, "could not allocate temporary memory for processing");
        free(temp1);
        return;
    }

    // Read from buffer

    buffer_read(source, read_chan, (float *) temp1, full_length);

    // Copy with crops / fades to double precision version

    for (i = 0; i < final_length; i++)
    {
        double in_val = temp1[i + crop1];
        double fade_in = calculate_fade((double) (i + crop1), fade_in_lo, fade_in_recip);
        double fade_out = calculate_fade((double) (i + crop1), fade_out_lo, fade_out_recip);

        temp2[i] = in_val * fade_in * fade_out;
    }

    // Copy out to buffer

    error = buffer_write(target, temp2, final_length, x->write_chan - 1, x->resize, sample_rate, 1.);
    buffer_write_error((t_object *)x, target, error);

    // Free Resources

    ALIGNED_FREE(temp1);

    if (!error)
        outlet_bang(x->process_done);
}
void irextract_noise (t_irextract *x, t_symbol *sym, long argc, t_atom *argv)
{
	double length = 10000;
	double fade_in = 10;
	double fade_out = 10;
	double amp_comp = 1.;
	double out_length = 0;
	double max_pink, max_brown;
	double sample_rate;
	
	t_atom_long num_channels = 1;

	t_symbol *rec_buffer = 0;
	
	t_noise_mode noise_mode = NOISE_MODE_WHITE;
	
	if (sym == gensym("brown"))
		noise_mode = NOISE_MODE_BROWN;
	if (sym == gensym("pink"))
		noise_mode = NOISE_MODE_PINK;
		
	// Load parameters
	
	if (argc > 0)
	{
		rec_buffer = atom_getsym(argv++);
		sample_rate = buffer_sample_rate(rec_buffer);
	}
	if (argc > 1)
		length = atom_getfloat(argv++);
	if (argc > 2)
		fade_in = atom_getfloat(argv++);
	if (argc > 3)
		fade_out = atom_getfloat(argv++);
	if (argc > 4)
		num_channels = atom_getlong(argv++);
	if (argc > 5)
		out_length = atom_getfloat(argv++);
	
	// Check parameters
	
	if (!rec_buffer)
	{
		object_error((t_object *)x, "no buffer given");
		return;
	}
	
	length = irextract_param_check(x, "length", length, 0., HUGE_VAL);
	fade_in = irextract_param_check(x, "fade in time", fade_in, 0., length / 2);
	fade_out = irextract_param_check(x, "fade out time", fade_out, 0., length / 2);
	num_channels = (t_atom_long) irextract_param_check(x, "number of channels", (double) num_channels, 1, HIRT_MAX_MEASURE_CHANS);
	x->out_length = irextract_param_check(x, "output length", out_length, 0., HUGE_VAL) / 1000.;

	// Process

	x->measure_mode = NOISE;
	coloured_noise_params(&x->noise_params, noise_mode, fade_in / 1000., fade_out / 1000., length / 1000., sample_rate, db_to_a(x->amp) / amp_comp);
	
	if (noise_mode != NOISE_MODE_WHITE)
	{
		coloured_noise_measure(&x->noise_params, (int) (length * sample_rate * 1000.), &max_pink, &max_brown);
		coloured_noise_reset(&x->noise_params);
	}
	if (noise_mode == NOISE_MODE_BROWN)
		amp_comp = max_brown;
	if (noise_mode == NOISE_MODE_PINK)
		amp_comp = max_pink;

	irextract_process(x, rec_buffer, num_channels, sample_rate);
}
void irextract_sweep (t_irextract *x, t_symbol *sym, long argc, t_atom *argv)
{			
	double f1 = 20;
	double f2 = 22050;
	double length = 30000;
	double fade_in = 50;
	double fade_out = 10;
	double out_length = 0;
	double sample_rate;
	
	double amp_curve[33];
	
	t_atom_long num_channels = 1;
	
	t_symbol *rec_buffer = 0;
	
	// Load parameters

	if (argc > 0)
	{
		rec_buffer = atom_getsym(argv++);
		sample_rate = buffer_sample_rate(rec_buffer);
		f2 = sample_rate / 2.;
	}
	if (argc > 1)
		f1 = atom_getfloat(argv++);
	if (argc > 2)
		f2 = atom_getfloat(argv++);
	if (argc > 3)
		length = atom_getfloat(argv++);
	if (argc > 4)
		fade_in = atom_getfloat(argv++);
	if (argc > 5)
		fade_out = atom_getfloat(argv++);
	if (argc > 6)
		num_channels = atom_getlong(argv++);
	if (argc > 7)
		out_length = atom_getfloat(argv++);
	
	// Check parameters
		
	if (!rec_buffer)
	{
		object_error((t_object *)x, "no buffer given");
		return;
	}
	
	f1 = irextract_param_check(x, "low frequency", f1, 0.0001, sample_rate / 2);
	f2 = irextract_param_check(x, "high frequency", f2, f2, sample_rate / 2);
	length = irextract_param_check(x, "length", length, 0., HUGE_VAL);
	fade_in = irextract_param_check(x, "fade in time", fade_in, 0., length / 2);
	fade_out = irextract_param_check(x, "fade out time", fade_out, 0., length / 2);
	num_channels = (t_atom_long) irextract_param_check(x, "number of channels", (double) num_channels, 1, HIRT_MAX_MEASURE_CHANS);
	x->out_length = irextract_param_check(x, "output length", out_length, 0., HUGE_VAL) / 1000.;
	
	// Check length of sweep and memory allocation
	
	fill_amp_curve_specifier(amp_curve, x->amp_curve_specifier, x->amp_curve_num_specifiers);
	
	if (ess_params(&x->sweep_params, f1, f2, fade_in / 1000., fade_out / 1000., length / 1000., sample_rate, db_to_a(x->amp), amp_curve))
	{
		// Process
		
		x->measure_mode = SWEEP;
		irextract_process(x, rec_buffer, num_channels, sample_rate);
	}
	else 
		object_error((t_object *) x, "zero length sweep - requested length value is too small");		
}