// ソフトウェアMIDIシンセサイザ。
// Copyright(c)2003-2004 yuno
#ifndef midisynth_hpp
#define midisynth_hpp

#include <map>
#include <memory>
#include <vector>

//namespace midisynth{
    typedef short int_least16_t;
    typedef unsigned short uint_least16_t;
//    typedef long int_least32_t;
//    typedef unsigned long uint_least32_t;
    typedef __int64 int_least64_t;
    typedef double sample_t;//added by Kobarin
    class channel;

    // システムモード列挙型。
    enum system_mode_t{ system_mode_default, system_mode_gm, system_mode_gm2, system_mode_gs, system_mode_xg };

    // コピー不可の基本クラス。
/*  削除 by Kobarin
    class uncopyable{
    public:
        uncopyable(){}
    private:
        uncopyable(const uncopyable&){}
        void operator=(const uncopyable&){}
    };
*/
    // ノート。発音中の音。
    class note{//:uncopyable{//修正 by Kobarin
    public:
        note(int assign_, int panpot_):assign(assign_), panpot(panpot_){}
        virtual ~note(){}
        int get_assign()const{ return assign; }
        int get_panpot()const{ return panpot; }
        virtual bool synthesize(sample_t* buf, std::size_t samples, double rate, sample_t left, sample_t right) = 0;
        virtual void note_off(int velocity) = 0;
        virtual void sound_off() = 0;
        virtual void set_frequency_multiplier(double value) = 0;
        virtual void set_tremolo(int depth, double freq) = 0;
        virtual void set_vibrato(double depth, double freq) = 0;
        virtual void set_damper(int value) = 0;
        virtual void set_sostenute(int value) = 0;
        virtual void set_freeze(int value) = 0;
    private:
        int assign;
        int panpot;
    };

    // ノートファクトリ。
    // ノートオンメッセージに対して適切なノートを作り出す。
    class note_factory{//:uncopyable{//修正 by Kobarin
    public:
        virtual note* note_on(int_least32_t program, int note, int velocity, double frequency_multiplier)=0;
    protected:
        ~note_factory(){}
    };

    // MIDIチャンネル。
    class channel{//:uncopyable{//修正 by Kobarin
        enum{ NUM_NOTES = 128 };
    public:
        channel(note_factory* factory, int bank);
        ~channel();

        int synthesize(sample_t* out, std::size_t samples, double rate, int_least32_t master_volume, int master_balance);
        void reset_all_parameters();
        void reset_all_controller();
        void all_note_off();
        void all_sound_off();
        void all_sound_off_immediately();

        void note_off(int note, int velocity);
        void note_on(int note, int velocity);
        void polyphonic_key_pressure(int note, int value);
        void program_change(int value){ set_program(128 * bank + value); }
        void channel_pressure(int value);
        void pitch_bend_change(int value){ pitch_bend = value; update_frequency_multiplier(); }
        void control_change(int control, int value);
        void bank_select(int value);

        void set_bank(int value){ bank = value; }
        void set_program(int value){ program = value; }
        void set_panpot(int value){ panpot = value; }
        void set_volume(int value){ volume = value; }
        void set_expression(int value){ expression = value; }
        void set_pitch_bend_sensitivity(int value){ pitch_bend_sensitivity = value; update_frequency_multiplier(); }
        void set_modulation_depth(int value){ modulation_depth = value; update_modulation(); }
        void set_modulation_depth_range(int value){ modulation_depth_range = value; update_modulation(); }
        void set_damper(int value);
        void set_sostenute(int value);
        void set_freeze(int value);
        void set_fine_tuning(int value){ fine_tuning = value; update_frequency_multiplier(); }
        void set_coarse_tuning(int value){ coarse_tuning = value; update_frequency_multiplier(); }
        void set_RPN(int value){ RPN = value; NRPN = 0x3FFF; }
        void set_NRPN(int value){ NRPN = value; RPN = 0x3FFF; }
        void set_tremolo_frequency(double value){ tremolo_frequency = value; }
        void set_vibrato_frequency(double value){ vibrato_frequency = value; }
        void set_master_frequency_multiplier(double value){ master_frequency_multiplier = value; update_frequency_multiplier(); }
        void set_mute(bool mute_){ mute = mute_; }
        void set_system_mode(system_mode_t mode){ system_mode = mode; }
        void mono_mode_on(){ all_note_off(); mono = true; }
        void poly_mode_on(){ all_note_off(); mono = false; }

        int get_program()const{ return program; }
        int get_bank()const{ return bank; }
        int get_panpot()const{ return panpot; }
        int get_volume()const{ return volume; }
        int get_expression()const{ return expression; }
        int get_channel_pressure()const{ return pressure; }
        int get_pitch_bend()const{ return pitch_bend; }
        int get_pitch_bend_sensitivity()const{ return pitch_bend_sensitivity; }
        int get_modulation_depth()const{ return modulation_depth; }
        int get_modulation_depth_range()const{ return modulation_depth_range; }
        int get_damper()const{ return damper; }
        int get_sostenute()const{ return sostenute; }
        int get_freeze()const{ return freeze; }
        int get_fine_tuning()const{ return fine_tuning; }
        int get_coarse_tuning()const{ return coarse_tuning; }
        int get_RPN()const{ return RPN; }
        int get_NRPN()const{ return NRPN; }
        double get_tremolo_frequency()const{ return tremolo_frequency; }
        double get_vibrato_frequency()const{ return vibrato_frequency; }
        bool get_mute()const{ return mute; }
        bool get_mono_mode()const{ return mono; }

    private:
        struct NOTE{
            class note* note;
            int key;
            enum STATUS{
                NOTEON, NOTEOFF, SOUNDOFF
            }status;
            NOTE(class note* p, int key_):note(p),key(key_),status(NOTEON){}
        };
        std::vector<NOTE> notes;
        note_factory* factory;
        int default_bank;
        int program;
        int bank;
        int panpot;
        int volume;
        int expression;
        int pressure;
        int pitch_bend;
        int pitch_bend_sensitivity;
        int modulation_depth;
        int modulation_depth_range;
        int damper;
        int sostenute;
        int freeze;
        int fine_tuning;
        int coarse_tuning;
        int RPN;
        int NRPN;
        bool mono;
        bool mute;
        double tremolo_frequency;
        double vibrato_frequency;
        double frequency_multiplier;
        double master_frequency_multiplier;
        system_mode_t system_mode;

        int get_registered_parameter();
        void set_registered_parameter(int value);
        void update_frequency_multiplier();
        void update_modulation();
    };

    // MIDIシンセサイザ。
    class synthesizer{//:uncopyable{//修正 by Kobarin
        enum{ NUM_CHANNELS = 16 };
    public:
        synthesizer(note_factory* factory);

        channel* get_channel(int ch);

        int synthesize(sample_t* output, std::size_t samples, double rate);
        int synthesize_mixing(sample_t* output, std::size_t samples, double rate);
        void reset();
        void reset_all_parameters();
        void reset_all_controller();
        void all_note_off();
        void all_sound_off();
        void all_sound_off_immediately();

        void note_on(int channel, int note, int velocity){ get_channel(channel)->note_on(note, velocity); }
        void note_off(int channel, int note, int velocity){ get_channel(channel)->note_off(note, velocity); }
        void polyphonic_key_pressure(int channel, int note, int value){ get_channel(channel)->polyphonic_key_pressure(note, value); }
        void control_change(int channel, int control, int value){ get_channel(channel)->control_change(control, value); }
        void program_change(int channel, int program){ get_channel(channel)->program_change(program); }
        void channel_pressure(int channel, int value){ get_channel(channel)->channel_pressure(value); }
        void pitch_bend_change(int channel, int value){ get_channel(channel)->pitch_bend_change(value); }
        void sysex_message(const void* data, std::size_t size);
        void midi_event(int command, int param1, int param2);
        void midi_event(uint_least32_t message){ midi_event(message & 0xFF, (message >> 8) & 0x7F, (message >> 16) & 0x7F); }

        void set_main_volume(int value){ main_volume = value; }
        void set_master_volume(int value){ master_volume = value; }
        void set_master_balance(int value){ master_balance = value; }
        void set_master_fine_tuning(int value){ master_fine_tuning = value; update_master_frequency_multiplier(); }
        void set_master_coarse_tuning(int value){ master_coarse_tuning = value; update_master_frequency_multiplier(); }
        void set_system_mode(system_mode_t mode);

        int get_main_volume()const{ return main_volume; }
        int get_master_volume()const{ return master_volume; }
        int get_master_balance()const{ return master_balance; }
        int get_master_fine_tuning()const{ return master_fine_tuning; }
        int get_master_coarse_tuning()const{ return master_coarse_tuning; }
        system_mode_t get_system_mode()const{ return system_mode; }

    private:
        std::auto_ptr<channel> channels[NUM_CHANNELS];
        double active_sensing;
        int main_volume;
        int master_volume;
        int master_balance;
        int master_fine_tuning;
        int master_coarse_tuning;
        double master_frequency_multiplier;
        system_mode_t system_mode;
        void update_master_frequency_multiplier();
    };

    // 正弦波生成器。
    // 振幅 32768 (-32767〜32767) の正弦波を生成する。
    class sine_wave_generator{
    public:
        sine_wave_generator();
        sine_wave_generator(double cycle);
        void set_cycle(double cycle);
        void add_modulation(int_least32_t x);
        int get_next();
        int get_next(int_least32_t modulation);
    private:
        uint_least32_t position;
        uint_least32_t step;
    };

    // エンベロープ生成器。
    // TL=0 のとき 0〜32767 の値を生成する。
    class envelope_generator{
    public:
        envelope_generator(int AR, int DR, int SR, int RR, int SL, int TL);
        void set_rate(double rate);
        void set_hold(double value);
        void set_freeze(double value);
        void key_off();
        void sound_off();
        bool is_finished()const{ return state == FINISHED; }
        int get_next();
    private:
        enum{ ATTACK, ATTACK_RELEASE, DECAY, DECAY_RELEASE, SASTAIN, RELEASE, SOUNDOFF, FINISHED }state;
        int AR, DR, SR, RR, TL;
        uint_least32_t fAR, fDR, fSR, fRR, fSL, fTL, fOR, fSS, fDRR, fDSS;
        uint_least32_t current;
        double rate;
        double hold;
        double freeze;
        void update_parameters();
    };

    // FMオペレータ (モジュレータおよびキャリア)。
    class fm_operator{
    public:
        fm_operator(int AR, int DR, int SR, int RR, int SL, int TL, int KS, int ML, int DT, int AMS, int key);
        void set_freq_rate(double freq, double rate);
        void set_hold(double value){ eg.set_hold(value); }
        void set_freeze(double value){ eg.set_freeze(value); }
        void add_modulation(int_least32_t x){ swg.add_modulation(x); }
        void key_off(){ eg.key_off(); }
        void sound_off(){ eg.sound_off(); }
        bool is_finished()const{ return eg.is_finished(); }
        int get_next();
        int get_next(int modulate);
        int get_next(int lfo, int modulate);
        inline int operator()(){ return get_next(); }
        inline int operator()(int m){ return get_next(m); }
        inline int operator()(int lfo, int m){ return get_next(lfo, m); }
    private:
        sine_wave_generator swg;
        envelope_generator eg;
        double ML;
        double DT;
        int_least32_t ams_factor;
        int_least32_t ams_bias;
    };

    // FM音源パラメータ。
    struct FMPARAMETER{
        int ALG, FB, LFO;
        struct{
            int AR, DR, SR, RR, SL, TL, KS, ML, DT, AMS;
        }op1, op2, op3, op4;
    };
    // ドラムパラメータ。
    struct DRUMPARAMETER:FMPARAMETER{
        int key, panpot, assign;
    };

    // FMサウンドジェネレータ。
    class fm_sound_generator{
    public:
        fm_sound_generator(const FMPARAMETER& params, int note, double frequency_multiplier);
        void set_rate(double rate);
        void set_frequency_multiplier(double value);
        void set_damper(int damper);
        void set_sostenute(int sostenute);
        void set_freeze(int freeze);
        void set_tremolo(int depth, double frequency);
        void set_vibrato(double depth, double frequency);
        void key_off();
        void sound_off();
        bool is_finished()const;
        int get_next();
    private:
        fm_operator op1;
        fm_operator op2;
        fm_operator op3;
        fm_operator op4;
        sine_wave_generator ams_lfo;
        sine_wave_generator vibrato_lfo;
        sine_wave_generator tremolo_lfo;
        int ALG;
        int FB;
        double freq;
        double freq_mul;
        double ams_freq;
        bool ams_enable;
        int tremolo_depth;
        double tremolo_freq;
        int vibrato_depth;
        double vibrato_freq;
        double rate;
        int feedback;
        int damper;
        int sostenute;
    };

    // FM音源ノート。
    class fm_note:public note{
    public:
        fm_note(const FMPARAMETER& params, int note, int velocity, int panpot, int assign, double frequency_multiplier);
        virtual void release(){ delete this; }
        virtual bool synthesize(sample_t* buf, std::size_t samples, double rate, sample_t left, sample_t right);
        virtual void note_off(int velocity);
        virtual void sound_off();
        virtual void set_frequency_multiplier(double value);
        virtual void set_tremolo(int depth, double freq);
        virtual void set_vibrato(double depth, double freq);
        virtual void set_damper(int value);
        virtual void set_sostenute(int value);
        virtual void set_freeze(int value);
    public:
        fm_sound_generator fm;
        int velocity;
    };

    // FM音源ノートファクトリ。
    class fm_note_factory:public note_factory{
    public:
        fm_note_factory();
        void clear();
        void get_program(int number, FMPARAMETER& p);
        bool set_program(int number, const FMPARAMETER& p);
        bool set_drum_program(int number, const DRUMPARAMETER& p);
        virtual note* note_on(int_least32_t program, int note, int velocity, double frequency_multiplier);
    private:
        std::map<int, FMPARAMETER> programs;
        std::map<int, DRUMPARAMETER> drums;
    };
//}

#endif
