
/*
 * CINELERRA
 * Copyright (C) 2008-2019 Adam Williams <broadcast at earthling dot net>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * 
 */

#ifndef REVERB_H
#define REVERB_H

class Reverb;
class ReverbEngine;
class ReverbFFT;

#include "fourier.h"
#include "reverbwindow.h"
#include "loadbalance.h"
#include "pluginaclient.h"

#define MAX_DELAY_INIT 1000
#define MIN_REFLECTIONS 1
#define MAX_REFLECTIONS 255
#define MIN_REFLENGTH 3
#define MAX_REFLENGTH 5000

class ReverbConfig
{
public:
	ReverbConfig();


	int equivalent(ReverbConfig &that);
	void copy_from(ReverbConfig &that);
	void interpolate(ReverbConfig &prev, 
		ReverbConfig &next, 
		int64_t prev_frame, 
		int64_t next_frame, 
		int64_t current_frame);
	void dump();
	void boundaries();

	float level_init;
	int delay_init;
	float ref_level1;
	float ref_level2;
	int ref_total;
	int ref_length;
// high frequency
	int high;
// low frequency
    int low;
    float q;
    int window_size;
};




class Reverb : public PluginAClient
{
public:
	Reverb(PluginServer *server);
	~Reverb();

	void update_gui();



// required for all realtime/multichannel plugins
	PLUGIN_CLASS_MEMBERS(ReverbConfig);
    int process_buffer(int64_t size, 
	    Samples **buffer, 
	    int64_t start_position,
	    int sample_rate);
    double gauss(double sigma, double center, double x);
    void calculate_envelope();
    void reallocate_dsp(int new_dsp_allocated);

	int is_realtime();
	int is_synthesis();
	int is_multichannel();
	void save_data(KeyFrame *keyframe);
	void read_data(KeyFrame *keyframe);

// the output all reflections are painted on
	double **dsp_in;
// may have to expand it for fft windows larger than the reflected time
    int dsp_in_allocated;
// total samples read into dsp_in by the FFT
	int dsp_in_length;
// new value calculated by the FFT readers
    int new_dsp_length;
// total spectrogram frames generated by the FFT.  Each channel overwrites the same
// spectrograms
    int new_spectrogram_frames;

// source channels of reflections
	int **ref_channels;
// destination offsets of reflections
    int **ref_offsets;
// levels of reflections
	double **ref_levels;
	int redo_buffers;
// detect seeking
    int64_t last_position;
	DB db;
// Spectrogram frames being populated by all the FFT's.
// Since multiple windows can be processed in a single process_buffer, the frames
// must be buffered before being added to the plugin.
    ArrayList<PluginClientFrame *> spectrogram_frames;

	ReverbEngine *engine;
    ReverbFFT **fft;
    double *envelope;
	int need_reconfigure;
};


class ReverbFFT :public CrossfadeFFT
{
public:
    ReverbFFT(Reverb *plugin, int channel);
    ~ReverbFFT();
    
    int signal_process();
	int post_process();
	int read_samples(int64_t output_sample, 
		int samples, 
		Samples *buffer);

    Reverb *plugin;
    int channel;
};




class ReverbPackage : public LoadPackage
{
public:
	ReverbPackage();
	int channel;
};


class ReverbUnit : public LoadClient
{
public:
	ReverbUnit(ReverbEngine *engine, Reverb *plugin);
	~ReverbUnit();
	void process_package(LoadPackage *package);
	ReverbEngine *engine;
	Reverb *plugin;
};

// This allocates 1 CPU for each output channel.  
// They simultaneously read from all the input FFT channels.
class ReverbEngine : public LoadServer
{
public:
	ReverbEngine(Reverb *plugin);
	~ReverbEngine();
	
	void init_packages();
	LoadClient* new_client();
	LoadPackage* new_package();
	
	Reverb *plugin;
};

#endif



