/*  SpiralSynth
 *  Copyleft (C) 2000 David Griffiths <dave@pawfal.org>
 *
 *  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.
*/ 

#include "OscillatorGUI.h"

static unsigned char *image_Square[] = {
(unsigned char*)"20 20 2 1",
(unsigned char*)" \tc None",
(unsigned char*)".\tc #000000",
(unsigned char*)"                    ",
(unsigned char*)"                    ",
(unsigned char*)"     ......         ",
(unsigned char*)"     .    .         ",
(unsigned char*)"     .    .         ",
(unsigned char*)"     .    .         ",
(unsigned char*)"     .    .         ",
(unsigned char*)"     .    .         ",
(unsigned char*)"     .    .         ",
(unsigned char*)"     .    .         ",
(unsigned char*)"   ...    .    ...  ",
(unsigned char*)"          .    .    ",
(unsigned char*)"          .    .    ",
(unsigned char*)"          .    .    ",
(unsigned char*)"          .    .    ",
(unsigned char*)"          .    .    ",
(unsigned char*)"          .    .    ",
(unsigned char*)"          ......    ",
(unsigned char*)"                    ",
(unsigned char*)"                    "};

static unsigned char *image_Noise[] = {
(unsigned char*)"20 20 2 1",
(unsigned char*)" \tc None",
(unsigned char*)".\tc #000000",
(unsigned char*)"                    ",
(unsigned char*)"                    ",
(unsigned char*)"                    ",
(unsigned char*)"                    ",
(unsigned char*)"            .       ",
(unsigned char*)"        .   .       ",
(unsigned char*)"        .  . .      ",
(unsigned char*)"        .  . .      ",
(unsigned char*)"       . . .  .     ",
(unsigned char*)"       . . .  .     ",
(unsigned char*)"   ... . . .  . ..  ",
(unsigned char*)"     . . . .  ..    ",
(unsigned char*)"     . . . .  .     ",
(unsigned char*)"     . .  .         ",
(unsigned char*)"      .   .         ",
(unsigned char*)"      .   .         ",
(unsigned char*)"      .   .         ",
(unsigned char*)"          .         ",
(unsigned char*)"                    ",
(unsigned char*)"                    "};

static unsigned char *image_Saw[] = {
(unsigned char*)"20 20 2 1",
(unsigned char*)" \tc None",
(unsigned char*)".\tc #000000",
(unsigned char*)"                    ",
(unsigned char*)"                    ",
(unsigned char*)"         ..         ",
(unsigned char*)"         ..         ",
(unsigned char*)"        . .         ",
(unsigned char*)"        . .         ",
(unsigned char*)"       .  .         ",
(unsigned char*)"       .  .         ",
(unsigned char*)"      .   .         ",
(unsigned char*)"      .   .         ",
(unsigned char*)"   ...    .   ....  ",
(unsigned char*)"          .   .     ",
(unsigned char*)"          .  .      ",
(unsigned char*)"          .  .      ",
(unsigned char*)"          . .       ",
(unsigned char*)"          . .       ",
(unsigned char*)"          ..        ",
(unsigned char*)"          ..        ",
(unsigned char*)"                    ",
(unsigned char*)"                    "};

OscillatorGUI::OscillatorGUI(Oscillator *o):
pixmap_Square(image_Square),
pixmap_Noise(image_Noise),
pixmap_Saw(image_Saw)
{
	m_osc=o;
	if (!m_osc) cerr<<"WARNING: Oscillator not correctly set up"<<endl;
}
		
void OscillatorGUI::CreateGUI(int xoff, int yoff, char *name)
{
	 Fl_Group* o = GUIOscGroup = new Fl_Group(xoff, yoff, 245, 110, name);
      o->type(1);
	  o->box(FL_UP_BOX);
      o->labeltype(FL_ENGRAVED_LABEL);
      o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
	  o->user_data((void*)(this));
       	  
	  ShapeSquare = new Fl_Check_Button(xoff+5, yoff+15, 55, 30);
      ShapeSquare->type(102);
      ShapeSquare->down_box(FL_DIAMOND_DOWN_BOX);
      ShapeSquare->selection_color(SpiralInfo::GUI_COLOUR);
      ShapeSquare->set();
      pixmap_Square.label(ShapeSquare);
	  ShapeSquare->callback((Fl_Callback*)cb_Square);
	              
	  ShapeNoise = new Fl_Check_Button(xoff+5, yoff+65, 55, 30);
      ShapeNoise->type(102);
      ShapeNoise->down_box(FL_DIAMOND_DOWN_BOX);
      ShapeNoise->selection_color(SpiralInfo::GUI_COLOUR);
      pixmap_Noise.label(ShapeNoise);      
      ShapeNoise->callback((Fl_Callback*)cb_Noise);
	  
	  ShapeSaw = new Fl_Check_Button(xoff+5, yoff+40, 55, 30);
      ShapeSaw->type(102);
      ShapeSaw->down_box(FL_DIAMOND_DOWN_BOX);
      ShapeSaw->selection_color(SpiralInfo::GUI_COLOUR);
      pixmap_Saw.label(ShapeSaw);      
      ShapeSaw->callback((Fl_Callback*)cb_Saw);
	  	   
	  Freq = new Fl_Knob(xoff+122, yoff+22, 55, 55, "Octave");
      Freq->color(SpiralInfo::GUI_COLOUR);
	  Freq->type(Fl_Knob::LINELIN);
      Freq->labelsize(10);
      Freq->maximum(6);
      Freq->step(1);
      Freq->value(3);   
	  Freq->scaleticks(6);
	  Freq->cursor(50);
	  Freq->callback((Fl_Callback*)cb_Freq);
	  
      FineTune = new Fl_Knob(xoff+188, yoff+2, 40, 40, "Fine Tune");
      FineTune->color(SpiralInfo::GUI_COLOUR);
	  FineTune->type(Fl_Knob::LINELIN);
      FineTune->labelsize(10);
      FineTune->maximum(2.0);
      FineTune->step(0.0001);
      FineTune->value(1);  
	  FineTune->callback((Fl_Callback*)cb_FineTune);
      
	  ModAmount = new Fl_Knob(xoff+188, yoff+54, 40, 40, "Mod Depth");
      ModAmount->color(SpiralInfo::GUI_COLOUR);
	  ModAmount->type(Fl_Knob::LINELIN);
	  ModAmount->labelsize(10);
      ModAmount->maximum(0.1);
      ModAmount->step(0.001);
      ModAmount->value(0.01);
      ModAmount->callback((Fl_Callback*)cb_ModAmount);
             
	  PulseWidth = new Fl_Slider(xoff+60, yoff+20, 20, 70, "PW");
	  PulseWidth->type(4);
	  PulseWidth->selection_color(SpiralInfo::GUI_COLOUR);
      PulseWidth->labelsize(10);
	  PulseWidth->maximum(1);
      PulseWidth->step(0.01);
      PulseWidth->value(0.5);
      PulseWidth->callback((Fl_Callback*)cb_PulseWidth);
	  
	  SHLen = new Fl_Slider(xoff+80, yoff+20, 20, 70, "SH");
	  SHLen->type(4);
	  SHLen->selection_color(SpiralInfo::GUI_COLOUR);
      SHLen->labelsize(10);
	  SHLen->maximum(0.2);
      SHLen->step(0.001);
      SHLen->value(0.1);
      SHLen->callback((Fl_Callback*)cb_SHLen);
	       
      Portmento = new Fl_Slider(xoff+100, yoff+20, 20, 70, "PM");
	  Portmento->type(4);
	  Portmento->selection_color(SpiralInfo::GUI_COLOUR);
      Portmento->labelsize(10);
	  Portmento->maximum(1.0);
      Portmento->step(0.001);
      Portmento->value(0.9);
      Portmento->callback((Fl_Callback*)cb_Portmento);
	  	       
   o->end();
    
}

void OscillatorGUI::UpdateValues()
{		 
	ShapeSquare->value(0);
	ShapeNoise->value(0);
	ShapeSaw->value(0);

	switch (m_osc->GetType())
	{
		case Oscillator::SQUARE : ShapeSquare->value(1); break;
		case Oscillator::NOISE  : ShapeNoise->value(1); break;
		case Oscillator::SAW    : ShapeSaw->value(1); break;
		case Oscillator::NONE   : break;
	}

	Freq->value(m_osc->GetOctave()+3);
	ModAmount->value(m_osc->GetModAmount());
	FineTune->value(m_osc->GetFineFreq());
	PulseWidth->value(m_osc->GetPulseWidth());
	
	SHLen->value(0.2f-m_osc->GetSHLen());
	
	if (m_osc->GetPortmento()==0)
	{
		Portmento->value(1.0f);
	}
	else Portmento->value(m_osc->GetPortmento()-0.001f);
}

void OscillatorGUI::MidiPitchBend(int amount) 
{
	FineTune->value(amount/64.0f); 
	m_osc->SetFineFreq(FineTune->value());
}

//// Callbacks ////

inline void OscillatorGUI::cb_Freq_i(Fl_Knob* o, void* v) 
{ m_osc->SetOctave(o->value()-3); }
void OscillatorGUI::cb_Freq(Fl_Knob* o, void* v) 
{ ((OscillatorGUI*)(o->parent()->user_data()))->cb_Freq_i(o,v); }

inline void OscillatorGUI::cb_FineTune_i(Fl_Knob* o, void* v) 
{ m_osc->SetFineFreq(o->value()); }
void OscillatorGUI::cb_FineTune(Fl_Knob* o, void* v) 
{ ((OscillatorGUI*)(o->parent()->user_data()))->cb_FineTune_i(o,v); }

inline void OscillatorGUI::cb_PulseWidth_i(Fl_Slider* o, void* v) 
{ m_osc->SetPulseWidth(o->value()); }
void OscillatorGUI::cb_PulseWidth(Fl_Slider* o, void* v) 
{ ((OscillatorGUI*)(o->parent()->user_data()))->cb_PulseWidth_i(o,v);}

inline void OscillatorGUI::cb_Square_i(Fl_Check_Button* o, void* v)
{ m_osc->SetType(Oscillator::SQUARE); }
void OscillatorGUI::cb_Square(Fl_Check_Button* o, void* v)
{ ((OscillatorGUI*)(o->parent()->user_data()))->cb_Square_i(o,v); }

inline void OscillatorGUI::cb_Saw_i(Fl_Check_Button* o, void* v)
{ m_osc->SetType(Oscillator::SAW); }
void OscillatorGUI::cb_Saw(Fl_Check_Button* o, void* v)
{ ((OscillatorGUI*)(o->parent()->user_data()))->cb_Saw_i(o,v); }

inline void OscillatorGUI::cb_Noise_i(Fl_Check_Button* o, void* v)
{ m_osc->SetType(Oscillator::NOISE); }
void OscillatorGUI::cb_Noise(Fl_Check_Button* o, void* v)
{ ((OscillatorGUI*)(o->parent()->user_data()))->cb_Noise_i(o,v); }

inline void OscillatorGUI::cb_SHLen_i(Fl_Slider* o, void* v)
{ m_osc->SetSHLen(0.2f-o->value()); }
void OscillatorGUI::cb_SHLen(Fl_Slider* o, void* v)
{ ((OscillatorGUI*)(o->parent()->user_data()))->cb_SHLen_i(o,v); }

inline void OscillatorGUI::cb_ModAmount_i(Fl_Knob* o, void* v)
{ m_osc->SetModAmount(o->value()); }
void OscillatorGUI::cb_ModAmount(Fl_Knob* o, void* v)
{ ((OscillatorGUI*)(o->parent()->user_data()))->cb_ModAmount_i(o,v); }

inline void OscillatorGUI::cb_Portmento_i(Fl_Slider* o, void* v)
{ 
if (o->value()==1.0f) m_osc->SetPortmento(0);
else m_osc->SetPortmento(o->value()+0.001f);
}
void OscillatorGUI::cb_Portmento(Fl_Slider* o, void* v)
{ ((OscillatorGUI*)(o->parent()->user_data()))->cb_Portmento_i(o,v); }


/////////////////////////////////////////////////////////


LFOGUI::LFOGUI(Oscillator *o) : OscillatorGUI(o)
{
}

void LFOGUI::CreateGUI(int xoff, int yoff, char *name)
{
	 Fl_Group* o = GUIOscGroup = new Fl_Group(xoff, yoff, 170, 110, name);
      o->type(1);
	  o->box(FL_UP_BOX);
      o->labeltype(FL_ENGRAVED_LABEL);
      o->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
	  o->user_data((void*)(this));
       	  
	  ShapeSquare = new Fl_Check_Button(xoff+5, yoff+15, 55, 30);
      ShapeSquare->type(102);
      ShapeSquare->down_box(FL_DIAMOND_DOWN_BOX);
      ShapeSquare->selection_color(SpiralInfo::GUI_COLOUR);
      ShapeSquare->set();
      pixmap_Square.label(ShapeSquare);
	  ShapeSquare->callback((Fl_Callback*)cb_Square);
	              
	  ShapeNoise = new Fl_Check_Button(xoff+5, yoff+65, 55, 30);
      ShapeNoise->type(102);
      ShapeNoise->down_box(FL_DIAMOND_DOWN_BOX);
      ShapeNoise->selection_color(SpiralInfo::GUI_COLOUR);
      pixmap_Noise.label(ShapeNoise);      
      ShapeNoise->callback((Fl_Callback*)cb_Noise);
	  
	  ShapeSaw = new Fl_Check_Button(xoff+5, yoff+40, 55, 30);
      ShapeSaw->type(102);
      ShapeSaw->down_box(FL_DIAMOND_DOWN_BOX);
      ShapeSaw->selection_color(SpiralInfo::GUI_COLOUR);
      pixmap_Saw.label(ShapeSaw);      
      ShapeSaw->callback((Fl_Callback*)cb_Saw);
	  	     
      FineTune = new Fl_Knob(xoff+118, yoff+30, 45, 45, "Frequency");
      FineTune->color(SpiralInfo::GUI_COLOUR);
	  FineTune->type(Fl_Knob::LINELIN);
      FineTune->labelsize(10);
      FineTune->maximum(2.0);
      FineTune->step(0.001);
      FineTune->value(0.5);   
	  FineTune->cursor(50);   
	  FineTune->callback((Fl_Callback*)cb_FineTune);
      	        
	  PulseWidth = new Fl_Slider(xoff+55, yoff+15, 20, 70, "PW");
	  PulseWidth->type(4);
	  PulseWidth->selection_color(SpiralInfo::GUI_COLOUR);
      PulseWidth->labelsize(10);
	  PulseWidth->maximum(1);
      PulseWidth->step(0.01);
      PulseWidth->value(0.5);
      PulseWidth->callback((Fl_Callback*)cb_PulseWidth);
	  
	  SHLen = new Fl_Slider(xoff+75, yoff+15, 20, 70, "SH");
	  SHLen->type(4);
	  SHLen->selection_color(SpiralInfo::GUI_COLOUR);
      SHLen->labelsize(10);
	  SHLen->maximum(0.2);
      SHLen->step(0.001);
      SHLen->value(0.1);
      SHLen->callback((Fl_Callback*)cb_SHLen);

	  Volume = new Fl_Slider(xoff+95, yoff+15, 20, 70, "Depth");
	  Volume->type(4);
	  Volume->selection_color(SpiralInfo::GUI_COLOUR);
      Volume->labelsize(10);
	  Volume->maximum(100);
      Volume->step(1);
      Volume->value(50);
      Volume->callback((Fl_Callback*)cb_Volume);
	       
      o->end();
    
}

void LFOGUI::UpdateValues()
{		 
	ShapeSquare->value(0);
	ShapeNoise->value(0);
	ShapeSaw->value(0);

	switch (m_osc->GetType())
	{
		case Oscillator::SQUARE : ShapeSquare->value(1); break;
		case Oscillator::NOISE  : ShapeNoise->value(1); break;
		case Oscillator::SAW    : ShapeSaw->value(1); break;
		case Oscillator::NONE   : break;
	}

	FineTune->value(sqrt(m_osc->GetFineFreq()));
	PulseWidth->value(m_osc->GetPulseWidth());
	SHLen->value(0.2+m_osc->GetSHLen());
}

inline void LFOGUI::cb_FineTune_i(Fl_Knob* o, void* v) 
{ 
	float value=o->value();
	m_osc->SetFineFreq(value*value); 
}
void LFOGUI::cb_FineTune(Fl_Knob* o, void* v) 
{ ((LFOGUI*)(o->parent()->user_data()))->cb_FineTune_i(o,v); }

inline void LFOGUI::cb_Volume_i(Fl_Slider* o, void* v) 
{ m_osc->SetVolume(0,100-o->value());}
void LFOGUI::cb_Volume(Fl_Slider* o, void* v) 
{ ((LFOGUI*)(o->parent()->user_data()))->cb_Volume_i(o,v); }
