/////////////////////////////////////////////////////////////////////////////
// Name:       	playwithvoice.h
// Purpose:  
// Author:      Cesar Mauri Loba (cesar at crea-si dot com)
// Modified by: 
// Created:     
// Copyright:   (C) 2010 Cesar Mauri Loba - CREA Software Systems
// 
//  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 3 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, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////
#ifndef PLAYWITHVOICE_H_
#define PLAYWITHVOICE_H_

/*!
 * Includes
 */

////@begin includes
#include "wx/gbsizer.h"
#include "wx/statline.h"
////@end includes
#include "valuerange.h"
#include "puredatawrapper.h"
#include "oscinout.h"

#include "spcore/component.h"
#include "spcore/pinimpl.h"
#include "spcore/basictypes.h"

/*!
 * Forward declarations
 */

////@begin forward declarations
////@end forward declarations

/*!
 * Control identifiers
 */

////@begin control identifiers
#define ID_PLAY_WITH_VOICE_PANEL 10021
#define ID_BITMAPBUTTON_MICINPUT 10016
#define ID_SLIDER_MIC_INPUT 10022
#define ID_GAUGE_MIC_INPUT 10023
#define ID_BITMAPBUTTON_SOUNDOUTPUT 10017
#define ID_SLIDER_OUTPUT 10000
#define ID_GAUGE_OUTPUT 10001
#define ID_CHECKBOX_MICBOOST 10028
#define ID_BITMAPBUTTON_REVERB 10026
#define ID_SLIDER_REVERB 10002
#define ID_TEXTCTRL_REVERB 10005
#define ID_BITMAPBUTTON_CHORUS 10006
#define ID_SLIDER_CHORUS 10010
#define ID_TEXTCTRL_CHORUS 10011
#define ID_BITMAPBUTTON_PITCHSHIFT 10009
#define ID_SLIDER_PITCHSHIFT 10007
#define ID_TEXTCTRL_PITCHSHIFT 10008
#define ID_BITMAPBUTTON_DISTORSION 10018
#define ID_SLIDER_DISTORSION 10019
#define ID_TEXTCTRL_DISTORSION 10025
#define ID_CHECKBOX_ROBOT 10014
#define ID_CHECKBOX_HOWLINGREDUCTION 10027
#define ID_CHECKBOX_PHONE 10015
#define ID_BITMAPBUTTON_ECHODELAY 10012
#define ID_SLIDER_ECHODELAY 10020
#define ID_TEXTCTRL_ECHODELAY 10024
#define ID_BITMAPBUTTON_ECHOPITCHSHIFT 10013
#define ID_SLIDER_ECHOPITCHSHIFT 10003
#define ID_TEXTCTRL_ECHOPITCHSHIFT 10004
#define SYMBOL_PLAYWITHVOICEPANEL_STYLE wxTAB_TRAVERSAL
#define SYMBOL_PLAYWITHVOICEPANEL_TITLE _("Playing with the Voice")
#define SYMBOL_PLAYWITHVOICEPANEL_IDNAME ID_PLAY_WITH_VOICE_PANEL
#define SYMBOL_PLAYWITHVOICEPANEL_SIZE wxSize(400, 300)
#define SYMBOL_PLAYWITHVOICEPANEL_POSITION wxDefaultPosition
////@end control identifiers

namespace mod_puredata {

class PlayWithVoiceComponent;

/*!
 * PlayWithVoicePanel class declaration
 */

class PlayWithVoicePanel: public wxPanel
{    
    DECLARE_DYNAMIC_CLASS( PlayWithVoicePanel )
    DECLARE_EVENT_TABLE()
public:
    /// Constructors
    PlayWithVoicePanel();
    PlayWithVoicePanel( wxWindow* parent, wxWindowID id = SYMBOL_PLAYWITHVOICEPANEL_IDNAME, const wxPoint& pos = SYMBOL_PLAYWITHVOICEPANEL_POSITION, const wxSize& size = SYMBOL_PLAYWITHVOICEPANEL_SIZE, long style = SYMBOL_PLAYWITHVOICEPANEL_STYLE, const wxString& name = SYMBOL_PLAYWITHVOICEPANEL_TITLE );

    bool Create( wxWindow* parent, wxWindowID id = SYMBOL_PLAYWITHVOICEPANEL_IDNAME, const wxPoint& pos = SYMBOL_PLAYWITHVOICEPANEL_POSITION, const wxSize& size = SYMBOL_PLAYWITHVOICEPANEL_SIZE, long style = SYMBOL_PLAYWITHVOICEPANEL_STYLE, const wxString& name = SYMBOL_PLAYWITHVOICEPANEL_TITLE );

     /// Destructor
    ~PlayWithVoicePanel();

	// Set destruction callback. NULL removes.
	void SetComponent( PlayWithVoiceComponent* component) { m_component= component; }

	// On component updated
	void NotifyComponentUpdate(); 

private:
    /// Initialises member variables
    void Init();

    /// Creates the controls and sizers
    void CreateControls();

////@begin PlayWithVoicePanel event handler declarations

#if defined(__WXOS2__)
    /// wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BITMAPBUTTON_MICINPUT
    void OnBitmapbuttonMicinputClick( wxCommandEvent& event );

#endif
#if defined(__WXOS2__)
    /// wxEVT_COMMAND_SLIDER_UPDATED event handler for ID_SLIDER_MIC_INPUT
    void OnSliderMicInputUpdated( wxCommandEvent& event );

#endif
    /// wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BITMAPBUTTON_SOUNDOUTPUT
    void OnBitmapbuttonSoundoutputClick( wxCommandEvent& event );

    /// wxEVT_COMMAND_SLIDER_UPDATED event handler for ID_SLIDER_OUTPUT
    void OnSliderOutputUpdated( wxCommandEvent& event );

    /// wxEVT_COMMAND_CHECKBOX_CLICKED event handler for ID_CHECKBOX_MICBOOST
    void OnCheckboxMicboostClick( wxCommandEvent& event );

    /// wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BITMAPBUTTON_REVERB
    void OnBitmapbuttonReverbClick( wxCommandEvent& event );

    /// wxEVT_COMMAND_SLIDER_UPDATED event handler for ID_SLIDER_REVERB
    void OnSliderReverbUpdated( wxCommandEvent& event );

    /// wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BITMAPBUTTON_CHORUS
    void OnBitmapbuttonChorusClick( wxCommandEvent& event );

    /// wxEVT_COMMAND_SLIDER_UPDATED event handler for ID_SLIDER_CHORUS
    void OnSliderChorusUpdated( wxCommandEvent& event );

    /// wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BITMAPBUTTON_PITCHSHIFT
    void OnBitmapbuttonPitchshiftClick( wxCommandEvent& event );

    /// wxEVT_COMMAND_SLIDER_UPDATED event handler for ID_SLIDER_PITCHSHIFT
    void OnSliderPitchshiftUpdated( wxCommandEvent& event );

    /// wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BITMAPBUTTON_DISTORSION
    void OnBitmapbuttonDistorsionClick( wxCommandEvent& event );

    /// wxEVT_COMMAND_SLIDER_UPDATED event handler for ID_SLIDER_DISTORSION
    void OnSliderDistorsionUpdated( wxCommandEvent& event );

#if defined(__WXOS2__)
    /// wxEVT_COMMAND_CHECKBOX_CLICKED event handler for ID_CHECKBOX_ROBOT
    void OnCheckboxRobotClick( wxCommandEvent& event );

#endif
    /// wxEVT_COMMAND_CHECKBOX_CLICKED event handler for ID_CHECKBOX_HOWLINGREDUCTION
    void OnCheckboxHowlingreductionClick( wxCommandEvent& event );

#if defined(__WXOS2__)
    /// wxEVT_COMMAND_CHECKBOX_CLICKED event handler for ID_CHECKBOX_PHONE
    void OnCheckboxPhoneClick( wxCommandEvent& event );

#endif
    /// wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BITMAPBUTTON_ECHODELAY
    void OnBitmapbuttonEchodelayClick( wxCommandEvent& event );

    /// wxEVT_COMMAND_SLIDER_UPDATED event handler for ID_SLIDER_ECHODELAY
    void OnSliderEchodelayUpdated( wxCommandEvent& event );

    /// wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BITMAPBUTTON_ECHOPITCHSHIFT
    void OnBitmapbuttonEchopitchshiftClick( wxCommandEvent& event );

    /// wxEVT_COMMAND_SLIDER_UPDATED event handler for ID_SLIDER_ECHOPITCHSHIFT
    void OnSliderEchopitchshiftUpdated( wxCommandEvent& event );

////@end PlayWithVoicePanel event handler declarations

//	void OnTimer(wxTimerEvent& event);
	void OnComponentUpdated( wxCommandEvent& event );

////@begin PlayWithVoicePanel member function declarations

    /// Retrieves bitmap resources
    wxBitmap GetBitmapResource( const wxString& name );

    /// Retrieves icon resources
    wxIcon GetIconResource( const wxString& name );
////@end PlayWithVoicePanel member function declarations

    /// Should we show tooltips?
    static bool ShowToolTips();

////@begin PlayWithVoicePanel member variables
#if defined(__WXOS2__)
    wxBitmapButton* m_btnMicInput;
#endif
#if defined(__WXOS2__)
    wxSlider* m_sldMicInput;
#endif
#if defined(__WXOS2__)
    wxGauge* m_gaugeMicInput;
#endif
    wxBitmapButton* m_btnSoundOutput;
    wxSlider* m_sldOutput;
    wxGauge* m_gaugeOutput;
    wxBitmapButton* m_btnReverb;
    wxSlider* m_sldReverb;
    wxTextCtrl* m_txtReverb;
    wxSlider* m_sldChorus;
    wxTextCtrl* m_txtChorus;
    wxSlider* m_sldPitchShift;
    wxTextCtrl* m_txtPitchShift;
    wxSlider* m_sldDistorsion;
    wxTextCtrl* m_txtDistorsion;
#if defined(__WXOS2__)
    wxCheckBox* m_chkRobot;
#endif
    wxCheckBox* m_chkHowlingReduction;
#if defined(__WXOS2__)
    wxCheckBox* m_chkPhone;
#endif
    wxSlider* m_sldEchoDelay;
    wxTextCtrl* m_txtEchoDelay;
    wxSlider* m_sldEchoPitchShift;
    wxTextCtrl* m_txtEchoPitchShift;
////@end PlayWithVoicePanel member variables
	PlayWithVoiceComponent* m_component;
	CValueRangeFExp m_logExpRangeEchoDelay;
	
	// Send a wxECVT_COMMAND_SLIDER_UPDATED event
	void UpdateSliderEvent(int id);

	// Put the value of a slider into a text box
	void Slider2TextCtrl(wxSlider* slider, wxTextCtrl* tb);
	// Put the value of a slider into a text box. Float version with optional scaling factor
	void Slider2TextCtrlF(wxSlider* slider, wxTextCtrl* tb, float fact= 1.0f);
	// Show a float number in a text box
	void TextCtrlF (float v, wxTextCtrl* tb);
};



/* ******************************************************************************
	the component
****************************************************************************** */
class PlayWithVoiceComponent 
	: public spcore::CComponentAdapter, public IPdPatch, public osc::OscPacketListener {

public:
	static const char* getTypeName() { return "play_with_voice"; };
	virtual const char* GetTypeName() const { return PlayWithVoiceComponent::getTypeName(); };

	PlayWithVoiceComponent (const char * name, int argc, const char * argv[]);

	virtual wxWindow* GetGUI(wxWindow * parent);
	void OnPanelDestroyed ();
	
	virtual bool ProvidesExecThread() const { return true; }
	
	virtual int DoStart();
    virtual void DoStop();
		
	//
	//
	//
	// Mic input
	void setMicInputControl(int v) { 
		m_micInputControl.setValue (v); SendSimpleMessageManaged ("/micInput", (float) v); 
	}
	CValueRangeI& getMicInputControl() { return m_micInputControl; }
	float getMicInputEnvelope() { return m_inEnvelope->getValue(); }

	// Sound output
	void setOutputControl(int v) { m_outputControl.setValue (v); SendSimpleMessageManaged ("/output", (float) v); }
	CValueRangeI& getOutputControl() { return m_outputControl; }
	float getOutputEnvelope() { return m_outEnvelope->getValue(); }

	// Reverb
	void setReverb(int v) { m_reverb.setValue (v); SendSimpleMessageManaged ("/reverb", (float) v); }
	CValueRangeI& getReverb() { return m_reverb; }

	// Chorus
	void setChorus(int v) { m_chorus.setValue (v); SendSimpleMessageManaged ("/chorus", (float) v); }
	CValueRangeI& getChorus() { return m_chorus; }

	// Pitch shift
	void setPitchShift(int v) { 
		m_pitchShift.setValue (v);
		if (m_howlingReduction && abs(v)< 5)
			SendSimpleMessageManaged ("/pitchShift", (float) 5);
		else
			SendSimpleMessageManaged ("/pitchShift", (float) v);	
	}
	CValueRangeI& getPitchShift() { return m_pitchShift; }

	// Distorsion
	void setDistorsion(int v) { m_distorsion.setValue (v); SendSimpleMessageManaged ("/distorsion", (float) v); }
	CValueRangeI& getDistorsion() { return m_distorsion; }

	// Robot
	void setRobot (bool v) { m_robot= v; SendSimpleMessageManaged ("/robot", (float) v); }
	bool getRobot () { return m_robot; }

	// Phone
	void setPhone (bool v) { m_phone= v; SendSimpleMessageManaged ("/phone", (float) v); }
	bool getPhone () { return m_phone; }

	// Howling reduction
	void setHowlingReduction (bool v) { 
		m_howlingReduction= v; 
		setPitchShift(m_pitchShift.getValue());
		setEchoPitchShift(m_echoPitchShift.getValue());
	}		
	bool getHowlingReduction () { return m_howlingReduction; }

	// Echo delay
	void setEchoDelay(int v) { m_echoDelay.setValue (v); SendSimpleMessageManaged ("/echoDelay", (float) v); }
	CValueRangeI& getEchoDelay() { return m_echoDelay; }

	// Echo pitch shift
	void setEchoPitchShift(int v) { 
		m_echoPitchShift.setValue (v); 
		if (m_howlingReduction && abs(v)< 5)
			SendSimpleMessageManaged ("/echoPitchShift", (float) 5);
		else 
			SendSimpleMessageManaged ("/echoPitchShift", (float) v); 
	}
	CValueRangeI& getEchoPitchShift() { return m_echoPitchShift; }

	//
	// IPdPatch methods
	//
	virtual void NotifyStatus (PDStatus e);
	virtual const char* GetPatchFileName() const;
	
private:
	void SendSimpleMessageManaged (const char *name, float v);
	virtual void ProcessMessage( const osc::ReceivedMessage& m, const IpEndpointName& remoteEndpoint );
	virtual ~PlayWithVoiceComponent();
	
	bool m_robot;
	bool m_phone;
	bool m_howlingReduction;
	bool m_running;

	PlayWithVoicePanel* m_panel;

	COscOut m_oscOut;
	COscIn m_oscIn;
	
	CValueRangeI m_micInputControl;

	CValueRangeI m_outputControl;

	CValueRangeI m_reverb;
	CValueRangeI m_chorus;
	CValueRangeI m_pitchShift;
	CValueRangeI m_distorsion;
	CValueRangeI m_echoDelay;
	CValueRangeI m_echoPitchShift;

	SmartPtr<spcore::IOutputPin> m_oPinInEnvelope;
	SmartPtr<spcore::IOutputPin> m_oPinOutEnvelope;
	SmartPtr<spcore::CTypeFloat> m_inEnvelope;
	SmartPtr<spcore::CTypeFloat> m_outEnvelope;

	std::string m_patchPath;
};

typedef spcore::ComponentFactory<PlayWithVoiceComponent> PlayWithVoiceComponentFactory;

};	// namespace end

#endif
    // PLAYWITHVOICE_H_
